diff --git a/Editor/Mono/2D/SpriteAtlas/EditorSpriteAtlas.bindings.cs b/Editor/Mono/2D/SpriteAtlas/EditorSpriteAtlas.bindings.cs index b3b86711c5..490e284a30 100644 --- a/Editor/Mono/2D/SpriteAtlas/EditorSpriteAtlas.bindings.cs +++ b/Editor/Mono/2D/SpriteAtlas/EditorSpriteAtlas.bindings.cs @@ -96,5 +96,6 @@ public static class SpriteAtlasExtensions extern internal static Texture2D[] GetPreviewAlphaTextures(this SpriteAtlas spriteAtlas); extern internal static TextureFormat GetTextureFormat(this SpriteAtlas spriteAtlas, BuildTarget target); extern internal static Sprite[] GetPackedSprites(this SpriteAtlas spriteAtlas); + extern internal static Hash128 GetStoredHash(this SpriteAtlas spriteAtlas); } } diff --git a/Editor/Mono/2D/SpriteAtlas/SpriteAtlasInspector.cs b/Editor/Mono/2D/SpriteAtlas/SpriteAtlasInspector.cs index 951f61703b..ca6d8ddcb1 100644 --- a/Editor/Mono/2D/SpriteAtlas/SpriteAtlasInspector.cs +++ b/Editor/Mono/2D/SpriteAtlas/SpriteAtlasInspector.cs @@ -64,7 +64,7 @@ class Styles public readonly GUIContent packButton = EditorGUIUtility.TrTextContent("Pack Preview", "Pack this atlas."); public readonly GUIContent disabledPackLabel = EditorGUIUtility.TrTextContent("Sprite Atlas packing is disabled. Enable it in Edit > Settings > Editor.", null, EditorGUIUtility.GetHelpIcon(MessageType.Info)); - public readonly GUIContent packableListLabel = EditorGUIUtility.TrTextContent("Objects for Packing", "Only accept Folder, Sprite Sheet(Texture) and Sprite."); + public readonly GUIContent packableListLabel = EditorGUIUtility.TrTextContent("Objects for Packing", "Only accept Folder, Sprite Sheet (Texture) and Sprite."); public readonly GUIContent notPowerOfTwoWarning = EditorGUIUtility.TrTextContent("This scale will produce a Sprite Atlas variant with a packed texture that is NPOT (non - power of two). This may cause visual artifacts in certain compression/texture formats."); @@ -96,6 +96,15 @@ public Styles() private static Styles s_Styles; + private static Styles styles + { + get + { + s_Styles = s_Styles ?? new Styles(); + return s_Styles; + } + } + private enum AtlasType { Undefined = -1, Master = 0, Variant = 1 } private SerializedProperty m_FilterMode; @@ -231,7 +240,7 @@ void AddPackable(ReorderableList list) { ObjectSelector.get.Show(null, typeof(Object), null, false); ObjectSelector.get.searchFilter = "t:sprite t:texture2d t:folder"; - ObjectSelector.get.objectSelectorID = s_Styles.packableSelectorHash; + ObjectSelector.get.objectSelectorID = styles.packableSelectorHash; } void RemovePackable(ReorderableList list) @@ -244,7 +253,7 @@ void RemovePackable(ReorderableList list) void DrawPackableElement(Rect rect, int index, bool selected, bool focused) { var property = m_Packables.GetArrayElementAtIndex(index); - var controlID = EditorGUIUtility.GetControlID(s_Styles.packableElementHash, FocusType.Passive); + var controlID = EditorGUIUtility.GetControlID(styles.packableElementHash, FocusType.Passive); var previousObject = property.objectReferenceValue; var changedObject = EditorGUI.DoObjectField(rect, rect, controlID, previousObject, typeof(Object), null, ValidateObjectForPackableFieldAssignment, false); @@ -263,8 +272,6 @@ void DrawPackableElement(Rect rect, int index, bool selected, bool focused) public override void OnInspectorGUI() { - s_Styles = s_Styles ?? new Styles(); - // Ensure changes done through script are reflected immediately in Inspector by Syncing m_TempPlatformSettings with Actual Settings. SyncPlatformSettings(); @@ -295,7 +302,7 @@ public override void OnInspectorGUI() || EditorSettings.spritePackerMode == SpritePackerMode.AlwaysOnAtlas); if (spriteAtlasPackignEnabled) { - if (GUILayout.Button(s_Styles.packButton, GUILayout.ExpandWidth(false))) + if (GUILayout.Button(styles.packButton, GUILayout.ExpandWidth(false))) { SpriteAtlas[] spriteAtlases = new SpriteAtlas[targets.Length]; for (int i = 0; i < spriteAtlases.Length; ++i) @@ -311,7 +318,7 @@ public override void OnInspectorGUI() } else { - if (GUILayout.Button(s_Styles.disabledPackLabel, EditorStyles.helpBox)) + if (GUILayout.Button(styles.disabledPackLabel, EditorStyles.helpBox)) { SettingsService.OpenProjectSettings("Project/Editor"); } @@ -330,7 +337,7 @@ private void HandleCommonSettingUI() EditorGUI.BeginChangeCheck(); EditorGUI.showMixedValue = atlasType == AtlasType.Undefined; - atlasType = (AtlasType)EditorGUILayout.IntPopup(s_Styles.atlasTypeLabel, (int)atlasType, s_Styles.atlasTypeOptions, s_Styles.atlasTypeValues); + atlasType = (AtlasType)EditorGUILayout.IntPopup(styles.atlasTypeLabel, (int)atlasType, styles.atlasTypeOptions, styles.atlasTypeValues); EditorGUI.showMixedValue = false; if (EditorGUI.EndChangeCheck()) { @@ -345,7 +352,7 @@ private void HandleCommonSettingUI() if (atlasType == AtlasType.Variant) { EditorGUI.BeginChangeCheck(); - EditorGUILayout.PropertyField(m_MasterAtlas, s_Styles.masterAtlasLabel); + EditorGUILayout.PropertyField(m_MasterAtlas, styles.masterAtlasLabel); if (EditorGUI.EndChangeCheck()) { // Apply modified properties here to have latest master atlas reflected in native codes. @@ -359,17 +366,17 @@ private void HandleCommonSettingUI() } } - EditorGUILayout.PropertyField(m_BindAsDefault, s_Styles.bindAsDefaultLabel); + EditorGUILayout.PropertyField(m_BindAsDefault, styles.bindAsDefaultLabel); } private void HandleVariantSettingUI() { - EditorGUILayout.LabelField(s_Styles.variantSettingLabel, EditorStyles.boldLabel); - EditorGUILayout.PropertyField(m_VariantScale, s_Styles.variantMultiplierLabel); + EditorGUILayout.LabelField(styles.variantSettingLabel, EditorStyles.boldLabel); + EditorGUILayout.PropertyField(m_VariantScale, styles.variantMultiplierLabel); // Test if the multiplier scale a power of two size (1024) into another power of 2 size. if (!Mathf.IsPowerOfTwo((int)(m_VariantScale.floatValue * 1024))) - EditorGUILayout.HelpBox(s_Styles.notPowerOfTwoWarning.text, MessageType.Warning, true); + EditorGUILayout.HelpBox(styles.notPowerOfTwoWarning.text, MessageType.Warning, true); } private void HandleBoolToIntPropertyField(SerializedProperty prop, GUIContent content) @@ -385,22 +392,22 @@ private void HandleBoolToIntPropertyField(SerializedProperty prop, GUIContent co private void HandleMasterSettingUI() { - EditorGUILayout.LabelField(s_Styles.packingParametersLabel, EditorStyles.boldLabel); + EditorGUILayout.LabelField(styles.packingParametersLabel, EditorStyles.boldLabel); - HandleBoolToIntPropertyField(m_EnableRotation, s_Styles.enableRotationLabel); - HandleBoolToIntPropertyField(m_EnableTightPacking, s_Styles.enableTightPackingLabel); - EditorGUILayout.IntPopup(m_Padding, s_Styles.paddingOptions, s_Styles.paddingValues, s_Styles.paddingLabel); + HandleBoolToIntPropertyField(m_EnableRotation, styles.enableRotationLabel); + HandleBoolToIntPropertyField(m_EnableTightPacking, styles.enableTightPackingLabel); + EditorGUILayout.IntPopup(m_Padding, styles.paddingOptions, styles.paddingValues, styles.paddingLabel); GUILayout.Space(EditorGUI.kSpacing); } private void HandleTextureSettingUI() { - EditorGUILayout.LabelField(s_Styles.textureSettingLabel, EditorStyles.boldLabel); + EditorGUILayout.LabelField(styles.textureSettingLabel, EditorStyles.boldLabel); - HandleBoolToIntPropertyField(m_Readable, s_Styles.readWrite); - HandleBoolToIntPropertyField(m_GenerateMipMaps, s_Styles.generateMipMapLabel); - HandleBoolToIntPropertyField(m_UseSRGB, s_Styles.sRGBLabel); + HandleBoolToIntPropertyField(m_Readable, styles.readWrite); + HandleBoolToIntPropertyField(m_GenerateMipMaps, styles.generateMipMapLabel); + HandleBoolToIntPropertyField(m_UseSRGB, styles.sRGBLabel); EditorGUILayout.PropertyField(m_FilterMode); var showAniso = !m_FilterMode.hasMultipleDifferentValues && !m_GenerateMipMaps.hasMultipleDifferentValues @@ -415,7 +422,7 @@ private void HandleTextureSettingUI() private void HandlePlatformSettingUI() { - int shownTextureFormatPage = EditorGUILayout.BeginPlatformGrouping(m_ValidPlatforms.ToArray(), s_Styles.defaultPlatformLabel); + int shownTextureFormatPage = EditorGUILayout.BeginPlatformGrouping(m_ValidPlatforms.ToArray(), styles.defaultPlatformLabel); var defaultPlatformSettings = m_TempPlatformSettings[TextureImporterInspector.s_DefaultPlatformName]; if (shownTextureFormatPage == -1) { @@ -515,11 +522,11 @@ private void HandlePackableListUI() } break; case EventType.ValidateCommand: - if (currentEvent.commandName == ObjectSelector.ObjectSelectorClosedCommand && ObjectSelector.get.objectSelectorID == s_Styles.packableSelectorHash) + if (currentEvent.commandName == ObjectSelector.ObjectSelectorClosedCommand && ObjectSelector.get.objectSelectorID == styles.packableSelectorHash) usedEvent = true; break; case EventType.ExecuteCommand: - if (currentEvent.commandName == ObjectSelector.ObjectSelectorClosedCommand && ObjectSelector.get.objectSelectorID == s_Styles.packableSelectorHash) + if (currentEvent.commandName == ObjectSelector.ObjectSelectorClosedCommand && ObjectSelector.get.objectSelectorID == styles.packableSelectorHash) { var obj = ObjectSelector.GetCurrentObject(); if (IsPackable(obj)) @@ -534,7 +541,7 @@ private void HandlePackableListUI() } // Handle Foldout after we handle the current event because Foldout might process the drag and drop event and used it. - m_PackableListExpanded = EditorGUI.Foldout(rect, m_PackableListExpanded, s_Styles.packableListLabel, true); + m_PackableListExpanded = EditorGUI.Foldout(rect, m_PackableListExpanded, styles.packableListLabel, true); if (usedEvent) currentEvent.Use(); @@ -593,7 +600,7 @@ public override void OnPreviewSettings() { // Do not allow changing of pages when multiple atlases is selected. if (targets.Length == 1 && m_OptionDisplays != null && m_OptionValues != null && m_TotalPages > 1) - m_PreviewPage = EditorGUILayout.IntPopup(m_PreviewPage, m_OptionDisplays, m_OptionValues, s_Styles.preDropDown, GUILayout.MaxWidth(50)); + m_PreviewPage = EditorGUILayout.IntPopup(m_PreviewPage, m_OptionDisplays, m_OptionValues, styles.preDropDown, GUILayout.MaxWidth(50)); else m_PreviewPage = 0; @@ -602,14 +609,14 @@ public override void OnPreviewSettings() Texture2D t = m_PreviewTextures[m_PreviewPage]; if (TextureUtil.HasAlphaTextureFormat(t.format) || (m_PreviewAlphaTextures != null && m_PreviewAlphaTextures.Length > 0)) - m_ShowAlpha = GUILayout.Toggle(m_ShowAlpha, m_ShowAlpha ? s_Styles.alphaIcon : s_Styles.RGBIcon, s_Styles.previewButton); + m_ShowAlpha = GUILayout.Toggle(m_ShowAlpha, m_ShowAlpha ? styles.alphaIcon : styles.RGBIcon, styles.previewButton); int mipCount = Mathf.Max(1, TextureUtil.GetMipmapCount(t)); if (mipCount > 1) { - GUILayout.Box(s_Styles.smallZoom, s_Styles.previewLabel); - m_MipLevel = Mathf.Round(GUILayout.HorizontalSlider(m_MipLevel, mipCount - 1, 0, s_Styles.previewSlider, s_Styles.previewSliderThumb, GUILayout.MaxWidth(64))); - GUILayout.Box(s_Styles.largeZoom, s_Styles.previewLabel); + GUILayout.Box(styles.smallZoom, styles.previewLabel); + m_MipLevel = Mathf.Round(GUILayout.HorizontalSlider(m_MipLevel, mipCount - 1, 0, styles.previewSlider, styles.previewSliderThumb, GUILayout.MaxWidth(64))); + GUILayout.Box(styles.largeZoom, styles.previewLabel); } } } diff --git a/Editor/Mono/Animation/AnimationWindow/AddCurvesPopupHierarchyDataSource.cs b/Editor/Mono/Animation/AnimationWindow/AddCurvesPopupHierarchyDataSource.cs index 5bea4058b3..17491a11bd 100644 --- a/Editor/Mono/Animation/AnimationWindow/AddCurvesPopupHierarchyDataSource.cs +++ b/Editor/Mono/Animation/AnimationWindow/AddCurvesPopupHierarchyDataSource.cs @@ -54,7 +54,7 @@ public override void FetchData() private TreeViewItem AddGameObjectToHierarchy(GameObject gameObject, GameObject rootGameObject, AnimationClip animationClip, TreeViewItem parent) { string path = AnimationUtility.CalculateTransformPath(gameObject.transform, rootGameObject.transform); - TreeViewItem node = new AddCurvesPopupGameObjectNode(gameObject, parent, gameObject.name); + AddCurvesPopupGameObjectNode node = new AddCurvesPopupGameObjectNode(gameObject, parent, gameObject.name); List childNodes = new List(); if (m_RootItem == null) @@ -111,6 +111,20 @@ private TreeViewItem AddGameObjectToHierarchy(GameObject gameObject, GameObject } } + var animator = rootGameObject.GetComponent(); + if (animator != null) + { + //If the Animator has a human avatar, we need to check if the avatar's hierarchy matches that of the current GameObject. If they do not match, disable the node. + if (animator.avatarRoot != null && animator.isHuman) + { + if (animator.avatarRoot.Find(path) == null) + { + node.disabled = true; + } + } + } + + if (showEntireHierarchy) { // Iterate over all child GOs @@ -220,6 +234,7 @@ public void UpdateData() internal class AddCurvesPopupGameObjectNode : TreeViewItem { + internal bool disabled = false; public AddCurvesPopupGameObjectNode(GameObject gameObject, TreeViewItem parent, string displayName) : base(gameObject.GetInstanceID(), parent != null ? parent.depth + 1 : -1, parent, displayName) { diff --git a/Editor/Mono/Animation/AnimationWindow/AddCurvesPopupHierarchyGUI.cs b/Editor/Mono/Animation/AnimationWindow/AddCurvesPopupHierarchyGUI.cs index 939b21cf85..b68a9cf804 100644 --- a/Editor/Mono/Animation/AnimationWindow/AddCurvesPopupHierarchyGUI.cs +++ b/Editor/Mono/Animation/AnimationWindow/AddCurvesPopupHierarchyGUI.cs @@ -6,6 +6,7 @@ using UnityEditor.IMGUI.Controls; using UnityEngine; using System.Collections.Generic; +using UnityEditor.ShortcutManagement; namespace UnityEditorInternal { @@ -18,17 +19,38 @@ internal class AddCurvesPopupHierarchyGUI : TreeViewGUI private GUIContent addPropertiesContent = EditorGUIUtility.TrTextContent("Add Properties"); private const float plusButtonWidth = 17; + static Texture2D warningIcon = (Texture2D)EditorGUIUtility.LoadRequired("Icons/ShortcutManager/alertDialog.png"); + public static GUIStyle warningIconStyle; + public AddCurvesPopupHierarchyGUI(TreeViewController treeView, EditorWindow owner) : base(treeView, true) { this.owner = owner; + warningIconStyle = new GUIStyle(); + warningIconStyle.margin = new RectOffset(15, 15, 15, 15); } public override void OnRowGUI(Rect rowRect, TreeViewItem node, int row, bool selected, bool focused) { - base.OnRowGUI(rowRect, node, row, selected, focused); - DoAddCurveButton(rowRect, node); - HandleContextMenu(rowRect, node); + bool propertyPathMismatchWithHumanAvatar = false; + AddCurvesPopupGameObjectNode addCurvesPopupNode = node as AddCurvesPopupGameObjectNode; + if (addCurvesPopupNode != null) + { + propertyPathMismatchWithHumanAvatar = addCurvesPopupNode.disabled; + } + + using (new EditorGUI.DisabledScope(propertyPathMismatchWithHumanAvatar)) + { + base.OnRowGUI(rowRect, node, row, selected, focused); + DoAddCurveButton(rowRect, node); + HandleContextMenu(rowRect, node); + } + + if (propertyPathMismatchWithHumanAvatar) + { + Rect iconRect = new Rect(rowRect.width - plusButtonWidth, rowRect.yMin, plusButtonWidth, plusButtonStyle.fixedHeight); + GUI.Label(iconRect, new GUIContent(warningIcon, "The Avatar definition does not match the property path. Please author using a hierarchy the Avatar was built with."), warningIconStyle); + } } private void DoAddCurveButton(Rect rowRect, TreeViewItem node) diff --git a/Editor/Mono/Animation/GameObjectRecorder.bindings.cs b/Editor/Mono/Animation/GameObjectRecorder.bindings.cs index 4014083f37..46f4063f0f 100644 --- a/Editor/Mono/Animation/GameObjectRecorder.bindings.cs +++ b/Editor/Mono/Animation/GameObjectRecorder.bindings.cs @@ -74,6 +74,9 @@ public void SaveToClip(AnimationClip clip) public void SaveToClip(AnimationClip clip, float fps) { + if (!isRecording) + throw new InvalidOperationException("Cannot save to clip as there is nothing to save. The method TakeSnapshot() has not been called."); + if (fps <= Mathf.Epsilon) throw new ArgumentException("FPS can't be 0.0 or less"); SaveToClipInternal(clip, fps); diff --git a/Editor/Mono/Animation/ZoomableArea.cs b/Editor/Mono/Animation/ZoomableArea.cs index 8ab4fd6020..b40e8c82ed 100644 --- a/Editor/Mono/Animation/ZoomableArea.cs +++ b/Editor/Mono/Animation/ZoomableArea.cs @@ -518,6 +518,20 @@ private Rect shownAreaInsideMarginsInternal } } + float GetWidthInsideMargins(float widthWithMargins, bool substractSliderWidth = false) + { + float width = (widthWithMargins < kMinWidth) ? kMinWidth : widthWithMargins; + float widthInsideMargins = width - leftmargin - rightmargin - (substractSliderWidth ? (m_VSlider ? styles.visualSliderWidth : 0) : 0); + return Mathf.Max(widthInsideMargins, kMinWidth); + } + + float GetHeightInsideMargins(float heightWithMargins, bool substractSliderHeight = false) + { + float height = (heightWithMargins < kMinHeight) ? kMinHeight : heightWithMargins; + float heightInsideMargins = height - topmargin - bottommargin - (substractSliderHeight ? (m_HSlider ? styles.visualSliderWidth : 0) : 0); + return Mathf.Max(heightInsideMargins, kMinHeight); + } + public virtual Bounds drawingBounds { get @@ -739,10 +753,11 @@ void SliderGUI() } min = shownXMin; max = shownXMin + shownXRange; + float rectWidthWithinMargins = GetWidthInsideMargins(rect.width, true); if (min > area.xMin) - min = Mathf.Min(min, max - rect.width / m_HScaleMax); + min = Mathf.Min(min, max - rectWidthWithinMargins / m_HScaleMax); if (max < area.xMax) - max = Mathf.Max(max, min + rect.width / m_HScaleMax); + max = Mathf.Max(max, min + rectWidthWithinMargins / m_HScaleMax); SetShownHRangeInsideMargins(min, max); } @@ -773,10 +788,11 @@ void SliderGUI() } min = -(shownYMin + shownYRange); max = -shownYMin; + float rectHeightWithinMargins = GetHeightInsideMargins(rect.height, true); if (min > area.yMin) - min = Mathf.Min(min, max - rect.height / m_VScaleMax); + min = Mathf.Min(min, max - rectHeightWithinMargins / m_VScaleMax); if (max < area.yMax) - max = Mathf.Max(max, min + rect.height / m_VScaleMax); + max = Mathf.Max(max, min + rectHeightWithinMargins / m_VScaleMax); SetShownVRangeInsideMargins(min, max); } else @@ -802,10 +818,11 @@ void SliderGUI() } min = shownYMin; max = shownYMin + shownYRange; + float rectHeightWithinMargins = GetHeightInsideMargins(rect.height, true); if (min > area.yMin) - min = Mathf.Min(min, max - rect.height / m_VScaleMax); + min = Mathf.Min(min, max - rectHeightWithinMargins / m_VScaleMax); if (max < area.yMax) - max = Mathf.Max(max, min + rect.height / m_VScaleMax); + max = Mathf.Max(max, min + rectHeightWithinMargins / m_VScaleMax); SetShownVRangeInsideMargins(min, max); } } @@ -906,59 +923,80 @@ public void SetTransform(Vector2 newTranslation, Vector2 newScale) public void EnforceScaleAndRange() { - // Minimum scale might also be constrained by maximum range - float constrainedHScaleMin = rect.width / m_HScaleMin; - float constrainedVScaleMin = rect.height / m_VScaleMin; - if (hRangeMax != Mathf.Infinity && hRangeMin != Mathf.NegativeInfinity) - constrainedHScaleMin = Mathf.Min(constrainedHScaleMin, hRangeMax - hRangeMin); - if (vRangeMax != Mathf.Infinity && vRangeMin != Mathf.NegativeInfinity) - constrainedVScaleMin = Mathf.Min(constrainedVScaleMin, vRangeMax - vRangeMin); - Rect oldArea = m_LastShownAreaInsideMargins; Rect newArea = shownAreaInsideMargins; if (newArea == oldArea) return; - float epsilon = 0.00001f; + float minChange = 0.01f; - if (newArea.width < oldArea.width - epsilon) - { - float xLerp = Mathf.InverseLerp(oldArea.width, newArea.width, rect.width / m_HScaleMax); - newArea = new Rect( - Mathf.Lerp(oldArea.x, newArea.x, xLerp), - newArea.y, - Mathf.Lerp(oldArea.width, newArea.width, xLerp), - newArea.height - ); - } - if (newArea.height < oldArea.height - epsilon) - { - float yLerp = Mathf.InverseLerp(oldArea.height, newArea.height, rect.height / m_VScaleMax); - newArea = new Rect( - newArea.x, - Mathf.Lerp(oldArea.y, newArea.y, yLerp), - newArea.width, - Mathf.Lerp(oldArea.height, newArea.height, yLerp) - ); - } - if (newArea.width > oldArea.width + epsilon) + if (!Mathf.Approximately(newArea.width, oldArea.width)) { - float xLerp = Mathf.InverseLerp(oldArea.width, newArea.width, constrainedHScaleMin); + float constrainedWidth = newArea.width; + if (newArea.width < oldArea.width) + { + // The shown area decreasing in size means the scale is increasing. This happens e.g. while zooming in. + // Only the max scale restricts the shown area size here, range has no influence. + constrainedWidth = GetWidthInsideMargins(drawRect.width / m_HScaleMax, false); + } + else + { + constrainedWidth = GetWidthInsideMargins(drawRect.width / m_HScaleMin, false); + + if (hRangeMax != Mathf.Infinity && hRangeMin != Mathf.NegativeInfinity) + { + // range only has an influence if it is enforced, i.e. not infinity + float denum = hRangeMax - hRangeMin; + if (denum < kMinWidth) denum = kMinWidth; + + constrainedWidth = Mathf.Min(constrainedWidth, denum); + } + } + + float xLerp = Mathf.InverseLerp(oldArea.width, newArea.width, constrainedWidth); + float newWidth = Mathf.Lerp(oldArea.width, newArea.width, xLerp); + float widthChange = Mathf.Abs(newWidth - newArea.width); newArea = new Rect( - Mathf.Lerp(oldArea.x, newArea.x, xLerp), + // only affect the position if there was any significant change in width + // this fixes an issue where if width was only different due to rounding issues, position changes are ignored as xLerp comes back 0 (or very nearly 0) + widthChange > minChange ? Mathf.Lerp(oldArea.x, newArea.x, xLerp) : newArea.x, newArea.y, - Mathf.Lerp(oldArea.width, newArea.width, xLerp), + newWidth, newArea.height ); } - if (newArea.height > oldArea.height + epsilon) + if (!Mathf.Approximately(newArea.height, oldArea.height)) { - float yLerp = Mathf.InverseLerp(oldArea.height, newArea.height, constrainedVScaleMin); + float constrainedHeight = newArea.height; + if (newArea.height < oldArea.height) + { + // The shown area decreasing in size means the scale is increasing. This happens e.g. while zooming in. + // Only the max scale restricts the shown area size here, range has no influence. + constrainedHeight = GetHeightInsideMargins(drawRect.height / m_VScaleMax, false); + } + else + { + constrainedHeight = GetHeightInsideMargins(drawRect.height / m_VScaleMin, false); + + if (vRangeMax != Mathf.Infinity && vRangeMin != Mathf.NegativeInfinity) + { + // range only has an influence if it is enforced, i.e. not infinity + float denum = vRangeMax - vRangeMin; + if (denum < kMinHeight) denum = kMinHeight; + constrainedHeight = Mathf.Min(constrainedHeight, denum); + } + } + + float yLerp = Mathf.InverseLerp(oldArea.height, newArea.height, constrainedHeight); + float newHeight = Mathf.Lerp(oldArea.height, newArea.height, yLerp); + float heightChange = Mathf.Abs(newHeight - newArea.height); newArea = new Rect( newArea.x, - Mathf.Lerp(oldArea.y, newArea.y, yLerp), + // only affect the position if there was any significant change in height + // this fixes an issue where if height was only different due to rounding issues, position changes are ignored as yLerp comes back 0 (or very nearly 0) + heightChange > minChange ? Mathf.Lerp(oldArea.y, newArea.y, yLerp) : newArea.y, newArea.width, - Mathf.Lerp(oldArea.height, newArea.height, yLerp) + newHeight ); } @@ -973,7 +1011,7 @@ public void EnforceScaleAndRange() newArea.y = vRangeMax - newArea.height; shownAreaInsideMarginsInternal = newArea; - m_LastShownAreaInsideMargins = newArea; + m_LastShownAreaInsideMargins = shownAreaInsideMargins; } public float PixelToTime(float pixelX, Rect rect) diff --git a/Editor/Mono/Annotation/AnnotationWindow.cs b/Editor/Mono/Annotation/AnnotationWindow.cs index fda295398e..0a10f4e1b5 100644 --- a/Editor/Mono/Annotation/AnnotationWindow.cs +++ b/Editor/Mono/Annotation/AnnotationWindow.cs @@ -75,7 +75,6 @@ private enum EnabledState readonly string textGizmoVisible = L10n.Tr("Show/Hide Gizmo"); GUIContent iconToggleContent = EditorGUIUtility.TrTextContent("", "Show/Hide Icon"); GUIContent iconSelectContent = EditorGUIUtility.TrTextContent("", "Select Icon"); - GUIContent icon3dGizmoContent = EditorGUIUtility.TrTextContent("3D Icons"); GUIContent showGridContent = EditorGUIUtility.TrTextContent("Show Grid"); GUIContent showOutlineContent = EditorGUIUtility.TrTextContent("Selection Outline"); @@ -592,21 +591,24 @@ void DrawListElement(Rect rect, bool even, AInfo ainfo) GUI.DrawTexture(div, EditorGUIUtility.whiteTexture, ScaleMode.StretchToFill); GUI.color = Color.white; - Rect arrowRect = iconRect; - arrowRect.x += 18; - arrowRect.y += 0; - arrowRect.width = 9; - - if (GUI.Button(arrowRect, iconSelectContent, m_Styles.iconDropDown)) + if (!ainfo.IsDisabled()) { - Object script = EditorGUIUtility.GetScript(ainfo.m_ScriptClass); - if (script != null) + Rect arrowRect = iconRect; + arrowRect.x += 18; + arrowRect.y += 0; + arrowRect.width = 9; + + if (GUI.Button(arrowRect, iconSelectContent, m_Styles.iconDropDown)) { - m_LastScriptThatHasShownTheIconSelector = ainfo.m_ScriptClass; - if (IconSelector.ShowAtPosition(script, arrowRect, true)) + Object script = EditorGUIUtility.GetScript(ainfo.m_ScriptClass); + if (script != null) { - IconSelector.SetMonoScriptIconChangedCallback(MonoScriptIconChanged); - GUIUtility.ExitGUI(); + m_LastScriptThatHasShownTheIconSelector = ainfo.m_ScriptClass; + if (IconSelector.ShowAtPosition(script, arrowRect, true)) + { + IconSelector.SetMonoScriptIconChangedCallback(MonoScriptIconChanged); + GUIUtility.ExitGUI(); + } } } } @@ -679,7 +681,7 @@ void SetGizmoState(AInfo ainfo, bool addToMostRecentChanged = true) internal class AInfo : System.IComparable, System.IEquatable { // Similar values as in Annotation (in AnnotationManager.h) - public enum Flags { kHasIcon = 1, kHasGizmo = 2 }; + public enum Flags { kHasIcon = 1, kHasGizmo = 2, kIsDisabled = 4 }; public AInfo(bool gizmoEnabled, bool iconEnabled, int flags, int classID, string scriptClass) { @@ -716,6 +718,11 @@ public bool HasIcon() return (m_Flags & (int)Flags.kHasIcon) > 0; } + public bool IsDisabled() + { + return (m_Flags & (int)Flags.kIsDisabled) > 0; + } + public int CompareTo(object obj) { AInfo other = obj as AInfo; diff --git a/Editor/Mono/Annotation/SceneViewCameraWindow.cs b/Editor/Mono/Annotation/SceneViewCameraWindow.cs index cb87c982ae..609c182343 100644 --- a/Editor/Mono/Annotation/SceneViewCameraWindow.cs +++ b/Editor/Mono/Annotation/SceneViewCameraWindow.cs @@ -30,18 +30,18 @@ public static void Init() readonly SceneView m_SceneView; GUIContent m_CameraSpeedSliderContent; + GUIContent m_AccelerationEnabled; GUIContent m_CameraSpeedMin; GUIContent m_CameraSpeedMax; GUIContent m_FieldOfView; GUIContent m_DynamicClip; GUIContent m_OcclusionCulling; GUIContent m_EasingEnabled; - GUIContent m_EasingDuration; const int kFieldCount = 12; const int kWindowWidth = 290; const int kWindowHeight = ((int)EditorGUI.kSingleLineHeight) * kFieldCount + kFrameWidth * 2; - const int kFrameWidth = 10; + const int kFrameWidth = 11; const float kPrefixLabelWidth = 120f; const float kMinSpeedLabelWidth = 25f; const float kMaxSpeedLabelWidth = 29f; @@ -61,13 +61,13 @@ public SceneViewCameraWindow(SceneView sceneView) m_SceneView = sceneView; m_CameraSpeedSliderContent = EditorGUIUtility.TrTextContent("Camera Speed", "The current speed of the camera in the Scene view."); + m_AccelerationEnabled = EditorGUIUtility.TrTextContent("Camera Acceleration", "Check this to enable acceleration when moving the camera. When enabled, camera speed is evaluated as a modifier. With acceleration disabled, the camera is accelerated to the Camera Speed."); m_CameraSpeedMin = EditorGUIUtility.TrTextContent("Min", "The minimum speed of the camera in the Scene view. Valid values are between [0.01, 98]."); m_CameraSpeedMax = EditorGUIUtility.TrTextContent("Max", "The maximum speed of the camera in the Scene view. Valid values are between [0.02, 99]."); m_FieldOfView = EditorGUIUtility.TrTextContent("Field of View", "The height of the camera's view angle. Measured in degrees vertically, or along the local Y axis."); m_DynamicClip = EditorGUIUtility.TrTextContent("Dynamic Clipping", "Check this to enable camera's near and far clipping planes to be calculated relative to the viewport size of the Scene."); m_OcclusionCulling = EditorGUIUtility.TrTextContent("Occlusion Culling", "Check this to enable occlusion culling in the Scene view. Occlusion culling disables rendering of objects when they\'re not currently seen by the camera because they\'re hidden (occluded) by other objects."); - m_EasingEnabled = EditorGUIUtility.TrTextContent("Camera Easing", "Check this to enable camera movement easing. This makes the camera ease in when it starts moving, and ease out when it stops."); - m_EasingDuration = EditorGUIUtility.TrTextContent("Duration", "How long it takes for the speed of the camera to accelerate to its initial full speed. Measured in seconds."); + m_EasingEnabled = EditorGUIUtility.TrTextContent("Camera Easing", "Check this to enable camera movement easing. This makes the camera ease in when it starts moving and ease out when it stops."); } public override void OnGUI(Rect rect) @@ -133,12 +133,7 @@ private void Draw(Rect rect) settings.easingEnabled = EditorGUILayout.Toggle(m_EasingEnabled, settings.easingEnabled); - using (new EditorGUI.DisabledScope(!settings.easingEnabled)) - { - EditorGUI.indentLevel += 1; - settings.easingDuration = EditorGUILayout.Slider(m_EasingDuration, settings.easingDuration, .1f, 2f); - EditorGUI.indentLevel -= 1; - } + settings.accelerationEnabled = EditorGUILayout.Toggle(m_AccelerationEnabled, settings.accelerationEnabled); settings.speed = EditorGUILayout.Slider(m_CameraSpeedSliderContent, settings.speed, settings.speedMin, settings.speedMax); diff --git a/Editor/Mono/AssemblyHelper.cs b/Editor/Mono/AssemblyHelper.cs index f298320d1b..f6b9bffcb5 100644 --- a/Editor/Mono/AssemblyHelper.cs +++ b/Editor/Mono/AssemblyHelper.cs @@ -263,6 +263,12 @@ public static string[] GetDefaultAssemblySearchPaths() foreach (var asm in precompiledAssemblies) searchPaths.Add(Path.GetDirectoryName(asm.Path)); + // Add Unity compiled assembly output directory. + // Required for MonoBehaviour derived types like UIBehaviour that + // were previous in a precompiled UnityEngine.UI.dll, but are now + // compiled in a package. + searchPaths.Add("Library/ScriptAssemblies"); + return searchPaths.ToArray(); } @@ -327,44 +333,12 @@ struct GetAssemblyResolverData public string[] SearchDirs; } - static GetAssemblyResolverData GetAssemblyResolver(BuildTarget targetPlatform, bool isEditor, string assemblyPathName, string[] searchDirs) - { - var target = ModuleManager.GetTargetStringFromBuildTarget(targetPlatform); - var extension = ModuleManager.GetCompilationExtension(target); - var extraPaths = extension.GetCompilerExtraAssemblyPaths(isEditor, assemblyPathName); - if (extraPaths != null && extraPaths.Length > 0) - { - var dirs = new List(searchDirs); - dirs.AddRange(extraPaths); - searchDirs = dirs.ToArray(); - } - - var assemblyResolver = extension.GetAssemblyResolver(isEditor, assemblyPathName, searchDirs); - - return new GetAssemblyResolverData - { - Resolver = assemblyResolver, - SearchDirs = searchDirs - }; - } - /// Extract information about all types in the specified assembly, searchDirs might be used to resolve dependencies. static public AssemblyTypeInfoGenerator.ClassInfo[] ExtractAssemblyTypeInfo(BuildTarget targetPlatform, bool isEditor, string assemblyPathName, string[] searchDirs) { try { - var assemblyResolverData = GetAssemblyResolver(targetPlatform, isEditor, assemblyPathName, searchDirs); - - AssemblyTypeInfoGenerator gen; - if (assemblyResolverData.Resolver == null) - { - gen = new AssemblyTypeInfoGenerator(assemblyPathName, assemblyResolverData.SearchDirs); - } - else - { - gen = new AssemblyTypeInfoGenerator(assemblyPathName, assemblyResolverData.Resolver); - } - + AssemblyTypeInfoGenerator gen = new AssemblyTypeInfoGenerator(assemblyPathName, searchDirs); return gen.GatherClassInfo(); } catch (System.Exception ex) @@ -426,16 +400,12 @@ public static RuntimeInitializeOnLoadMethodsData ExtractPlayerRuntimeInitializeO { try { - var assemblyResolverData = GetAssemblyResolver(targetPlatform, false, assemblyPath, searchDirs); - - if (assemblyResolverData.Resolver == null) - { - var resolver = new DefaultAssemblyResolver(); - foreach (var searchDir in searchDirs) - resolver.AddSearchDirectory(searchDir); + var assemblyResolverData = new GetAssemblyResolverData { SearchDirs = searchDirs, }; + var resolver = new DefaultAssemblyResolver(); + foreach (var searchDir in searchDirs) + resolver.AddSearchDirectory(searchDir); - assemblyResolverData.Resolver = resolver; - } + assemblyResolverData.Resolver = resolver; var assembly = AssemblyDefinition.ReadAssembly(assemblyPath, new ReaderParameters { diff --git a/Editor/Mono/AssemblyInfo/AssemblyInfo.cs b/Editor/Mono/AssemblyInfo/AssemblyInfo.cs index abff70b786..43a49dca68 100644 --- a/Editor/Mono/AssemblyInfo/AssemblyInfo.cs +++ b/Editor/Mono/AssemblyInfo/AssemblyInfo.cs @@ -99,6 +99,8 @@ [assembly: InternalsVisibleTo("Unity.InternalAPIEditorBridgeDev.005")] [assembly: InternalsVisibleTo("Unity.XR.Remoting.Editor")] [assembly: InternalsVisibleTo("UnityEngine.Common")] +[assembly: InternalsVisibleTo("Unity.UI.Builder.Editor")] +[assembly: InternalsVisibleTo("Unity.UI.Builder.EditorTests")] [assembly: InternalsVisibleTo("Unity.GraphViewTestUtilities.Editor")] [assembly: InternalsVisibleTo("Unity.ProBuilder.Editor")] [assembly: InternalsVisibleTo("Unity.2D.Sprite.Editor")] diff --git a/Editor/Mono/AssetDatabase/AssetDatabase.bindings.cs b/Editor/Mono/AssetDatabase/AssetDatabase.bindings.cs index e94d8fe00a..43cb7deac8 100644 --- a/Editor/Mono/AssetDatabase/AssetDatabase.bindings.cs +++ b/Editor/Mono/AssetDatabase/AssetDatabase.bindings.cs @@ -19,8 +19,16 @@ public enum ForceReserializeAssetsOptions ReserializeAssetsAndMetadata = ReserializeAssets | ReserializeMetadata } + internal enum ImportPackageOptions + { + Default = 0, + NoGUI = 1 << 0, + ImportDelayed = 1 << 1 + } + [NativeHeader("Modules/AssetDatabase/Editor/Public/AssetDatabase.h")] [NativeHeader("Modules/AssetDatabase/Editor/Public/AssetDatabaseUtility.h")] + [NativeHeader("Editor/Src/PackageUtility.h")] public partial class AssetDatabase { [FreeFunction("AssetDatabase::ReSerializeAssetsForced")] @@ -110,5 +118,18 @@ public static void ForceReserializeAssets() [FreeFunction("AssetDatabase::GUIDFromExistingAssetPath")] extern internal static GUID GUIDFromExistingAssetPath(string path); + + [FreeFunction("::ImportPackage")] + extern private static bool ImportPackage(string packagePath, ImportPackageOptions options); + //TODO: This API should be Obsoleted when there is time available to update all the uses of it in Package Manager packages + public static void ImportPackage(string packagePath, bool interactive) + { + ImportPackage(packagePath, ImportPackageOptions.ImportDelayed | (interactive ? ImportPackageOptions.Default : ImportPackageOptions.NoGUI)); + } + + internal static bool ImportPackageImmediately(string packagePath) + { + return ImportPackage(packagePath, ImportPackageOptions.NoGUI); + } } } diff --git a/Editor/Mono/AssetDatabase/AssetDatabase.cs b/Editor/Mono/AssetDatabase/AssetDatabase.cs index ebe376d4ee..41c1c0cb24 100644 --- a/Editor/Mono/AssetDatabase/AssetDatabase.cs +++ b/Editor/Mono/AssetDatabase/AssetDatabase.cs @@ -2,6 +2,8 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License +using System; +using System.Collections.Generic; using UnityEngine.Scripting; namespace UnityEditor @@ -53,5 +55,16 @@ private static void Internal_CallImportPackageFailed(string packageName, string if (importPackageFailed != null) importPackageFailed(packageName, errorMessage); } + + internal static void IsOpenForEdit(string[] assetOrMetaFilePaths, List outNotEditablePaths, StatusQueryOptions statusQueryOptions = StatusQueryOptions.UseCachedIfPossible) + { + if (assetOrMetaFilePaths == null) + throw new ArgumentNullException(nameof(assetOrMetaFilePaths)); + if (outNotEditablePaths == null) + throw new ArgumentNullException(nameof(outNotEditablePaths)); + UnityEngine.Profiling.Profiler.BeginSample("AssetDatabase.IsOpenForEdit"); + AssetModificationProcessorInternal.IsOpenForEdit(assetOrMetaFilePaths, outNotEditablePaths, statusQueryOptions); + UnityEngine.Profiling.Profiler.EndSample(); + } } } diff --git a/Editor/Mono/AssetDatabase/AssetPreview.bindings.cs b/Editor/Mono/AssetDatabase/AssetPreview.bindings.cs index 51d96b072d..44d04e28d4 100644 --- a/Editor/Mono/AssetDatabase/AssetPreview.bindings.cs +++ b/Editor/Mono/AssetDatabase/AssetPreview.bindings.cs @@ -30,6 +30,9 @@ internal static Texture2D GetAssetPreview(int instanceID) [FreeFunction("AssetPreviewBindings::GetAssetPreview")] internal static extern Texture2D GetAssetPreview(int instanceID, int clientID); + [FreeFunction("AssetPreviewBindings::HasAssetPreview")] + internal static extern bool HasAssetPreview(int instanceID, int clientID); + public static bool IsLoadingAssetPreview(int instanceID) { return IsLoadingAssetPreview(instanceID, kSharedClientID); diff --git a/Editor/Mono/AssetModificationProcessor.cs b/Editor/Mono/AssetModificationProcessor.cs index 251fa65154..ec42dbf5d3 100644 --- a/Editor/Mono/AssetModificationProcessor.cs +++ b/Editor/Mono/AssetModificationProcessor.cs @@ -8,6 +8,7 @@ using UnityEditor.VersionControl; using UnityEditorInternal; using UnityEditorInternal.VersionControl; +using System.Linq; using System.Reflection; namespace UnityEditor @@ -116,8 +117,12 @@ static void FileModeChanged(string[] assets, UnityEditor.VersionControl.FileMode // that we have the most recent status if (Provider.enabled) { - if (Provider.PromptAndCheckoutIfNeeded(assets, "")) + var editableAssets = new string[assets.Length]; + if (Provider.MakeEditable(assets, editableAssets)) + { + // TODO: handle partial results from MakeEditable i.e. editableassets Provider.SetFileMode(assets, mode); + } } } @@ -161,20 +166,21 @@ static void OnWillSaveAssets(string[] assets, out string[] assetsThatShouldBeSav } var assetsNotOpened = new List(); - foreach (string asset in assetsThatShouldBeSaved) - { - if (!AssetDatabase.IsOpenForEdit(asset, StatusQueryOptions.ForceUpdate)) - assetsNotOpened.Add(asset); - } + AssetDatabase.IsOpenForEdit(assetsThatShouldBeSaved, assetsNotOpened, StatusQueryOptions.ForceUpdate); assets = assetsNotOpened.ToArray(); - // Try to checkout if needed. This may fail but is catched below. - if (assets.Length != 0 && !Provider.PromptAndCheckoutIfNeeded(assets, "")) + // Try to checkout if needed. This may fail but is caught below. + var editableAssets = new string[assets.Length]; + if (assets.Length != 0 && !Provider.MakeEditable(assets, editableAssets)) { - Debug.LogError("Could not check out the following files in version control before saving: " + - string.Join(", ", assets)); - assetsThatShouldBeSaved = new string[0]; - return; + // only save assets that can be made editable (not locked by someone else, etc.), + // unless we are in the behavior mode that just overwrites everything anyway + if (!EditorUserSettings.overwriteFailedCheckoutAssets) + { + editableAssets = editableAssets.Where(a => a != null).ToArray(); + assetsThatShouldBeReverted = assets.Except(editableAssets).ToArray(); + assetsThatShouldBeSaved = assetsThatShouldBeSaved.Except(assetsThatShouldBeReverted).ToArray(); + } } } @@ -239,8 +245,8 @@ static AssetDeleteResult OnWillDeleteAsset(string assetPath, RemoveAssetOptions return finalResult; } - internal static MethodInfo[] isOpenForEditMethods = null; - internal static MethodInfo[] GetIsOpenForEditMethods() + static MethodInfo[] isOpenForEditMethods = null; + static MethodInfo[] GetIsOpenForEditMethods() { if (isOpenForEditMethods == null) { @@ -268,32 +274,77 @@ internal static MethodInfo[] GetIsOpenForEditMethods() return isOpenForEditMethods; } - internal static bool IsOpenForEdit(string assetPath, out string message, StatusQueryOptions statusOptions) + static bool IsAssetInReadOnlyFolder(string assetPath) { - message = ""; - if (String.IsNullOrEmpty(assetPath)) - return true; // assetPath can be empty in some cases where Unity is checking for stuff in Library folder - bool rootFolder, readOnly; bool validPath = AssetDatabase.GetAssetFolderInfo(assetPath, out rootFolder, out readOnly); - if (validPath && readOnly) - { - return false; - } - - bool finalResult = AssetModificationHook.IsOpenForEdit(assetPath, out message, statusOptions); + return validPath && readOnly; + } + static bool IsOpenForEditViaScriptCallbacks(string assetPath, ref string message) + { foreach (var method in GetIsOpenForEditMethods()) { object[] args = {assetPath, message}; - if (!((bool)method.Invoke(null, args))) + if (!(bool)method.Invoke(null, args)) { message = args[1] as string; return false; } } + return true; + } - return finalResult; + internal static bool IsOpenForEdit(string assetPath, out string message, StatusQueryOptions statusOptions) + { + message = string.Empty; + if (string.IsNullOrEmpty(assetPath)) + return true; // treat empty/null paths as editable (might be under Library folders etc.) + + if (IsAssetInReadOnlyFolder(assetPath)) + return false; + if (!AssetModificationHook.IsOpenForEdit(assetPath, out message, statusOptions)) + return false; + if (!IsOpenForEditViaScriptCallbacks(assetPath, ref message)) + return false; + + return true; + } + + internal static void IsOpenForEdit(string[] assetOrMetaFilePaths, List outNotEditablePaths, StatusQueryOptions statusQueryOptions = StatusQueryOptions.UseCachedIfPossible) + { + outNotEditablePaths.Clear(); + if (assetOrMetaFilePaths == null || assetOrMetaFilePaths.Length == 0) + return; + + var queryList = new List(); + foreach (var path in assetOrMetaFilePaths) + { + if (string.IsNullOrEmpty(path)) + continue; // treat empty/null paths as editable (might be under Library folders etc.) + if (IsAssetInReadOnlyFolder(path)) + { + outNotEditablePaths.Add(path); + continue; + } + queryList.Add(path); + } + + // check with VCS + AssetModificationHook.IsOpenForEdit(queryList, outNotEditablePaths, statusQueryOptions); + + // check with possible script callbacks + var scriptCallbacks = GetIsOpenForEditMethods(); + if (scriptCallbacks != null && scriptCallbacks.Length > 0) + { + var stillEditable = assetOrMetaFilePaths.Except(outNotEditablePaths).Where(f => !string.IsNullOrEmpty(f)); + var message = string.Empty; + foreach (var path in stillEditable) + { + if (!IsOpenForEditViaScriptCallbacks(path, ref message)) + outNotEditablePaths.Add(path); + } + } } internal static void OnStatusUpdated() diff --git a/Editor/Mono/AssetPipeline/TextureImporterTypes.bindings.cs b/Editor/Mono/AssetPipeline/TextureImporterTypes.bindings.cs index 67188cb7e1..fc912f5146 100644 --- a/Editor/Mono/AssetPipeline/TextureImporterTypes.bindings.cs +++ b/Editor/Mono/AssetPipeline/TextureImporterTypes.bindings.cs @@ -24,6 +24,7 @@ public struct SpriteMetaData [System.Serializable] [StructLayout(LayoutKind.Sequential)] [NativeAsStruct] + [NativeType(CodegenOptions.Custom, "TextureImporterSettings")] [NativeHeader("Editor/Src/AssetPipeline/TextureImporting/TextureImporter.bindings.h")] [NativeHeader("Editor/Src/AssetPipeline/TextureImporting/TextureImporterTypes.h")] public sealed partial class TextureImporterSettings diff --git a/Editor/Mono/AssetPostprocessor.cs b/Editor/Mono/AssetPostprocessor.cs index 540b9def3e..bb6272acb5 100644 --- a/Editor/Mono/AssetPostprocessor.cs +++ b/Editor/Mono/AssetPostprocessor.cs @@ -13,6 +13,8 @@ using System.Reflection; using Object = UnityEngine.Object; using UnityEditor.Experimental.AssetImporters; +using UnityEditorInternal; +using Unity.CodeEditor; namespace UnityEditor { @@ -86,8 +88,16 @@ static void PostprocessAllAssets(string[] importedAssets, string[] addedAssets, } Profiler.BeginSample("SyncVS.PostprocessSyncProject"); - ///@TODO: we need addedAssets for SyncVS. Make this into a proper API and write tests - SyncVS.PostprocessSyncProject(importedAssets, addedAssets, deletedAssets, movedAssets, movedFromPathAssets); + #pragma warning disable 618 + if (ScriptEditorUtility.GetScriptEditorFromPath(CodeEditor.CurrentEditorInstallation) == ScriptEditorUtility.ScriptEditor.Other) + { + CodeEditorProjectSync.PostprocessSyncProject(importedAssets, addedAssets, deletedAssets, movedAssets, movedFromPathAssets); + } + else + { + ///@TODO: we need addedAssets for SyncVS. Make this into a proper API and write tests + SyncVS.PostprocessSyncProject(importedAssets, addedAssets, deletedAssets, movedAssets, movedFromPathAssets); + } Profiler.EndSample(); } @@ -254,6 +264,16 @@ static void CleanupPostprocessors() } } + static bool ImplementsAnyOfTheses(Type type, string[] methods) + { + foreach (var method in methods) + { + if (type.GetMethod(method, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) != null) + return true; + } + return false; + } + [RequiredByNativeCode] static string GetMeshProcessorsHashString() { @@ -268,11 +288,20 @@ static string GetMeshProcessorsHashString() { var inst = Activator.CreateInstance(assetPostprocessorClass) as AssetPostprocessor; var type = inst.GetType(); - bool hasPreProcessMethod = type.GetMethod("OnPreprocessModel", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) != null; - bool hasPostprocessMeshHierarchy = type.GetMethod("OnPostprocessMeshHierarchy", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) != null; - bool hasPostProcessMethod = type.GetMethod("OnPostprocessModel", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) != null; + bool hasAnyPostprocessMethod = ImplementsAnyOfTheses(type, new[] + { + "OnPreprocessModel", + "OnPostprocessMeshHierarchy", + "OnPostprocessModel", + "OnPreprocessAnimation", + "OnPostprocessAnimation", + "OnPostprocessGameObjectWithAnimatedUserProperties", + "OnPostprocessGameObjectWithUserProperties", + "OnPostprocessMaterial", + "OnAssignMaterialModel" + }); uint version = inst.GetVersion(); - if (version != 0 && (hasPreProcessMethod || hasPostprocessMeshHierarchy || hasPostProcessMethod)) + if (version != 0 && hasAnyPostprocessMethod) { versionsByType.Add(type.FullName, version); } diff --git a/Editor/Mono/AssetStore/Json.cs b/Editor/Mono/AssetStore/Json.cs index 9f3431c893..02877138bf 100644 --- a/Editor/Mono/AssetStore/Json.cs +++ b/Editor/Mono/AssetStore/Json.cs @@ -18,6 +18,7 @@ using System.Collections.Generic; using System; +using System.Globalization; using UnityEngine; namespace UnityEditorInternal @@ -640,7 +641,7 @@ private JSONValue ParseNumber() try { - float f = System.Convert.ToSingle(resstr); + float f = System.Convert.ToSingle(resstr, CultureInfo.InvariantCulture); return new JSONValue(f); } catch (Exception) diff --git a/Editor/Mono/Audio/Mixer/GUI/AudioMixerChannelStripView.cs b/Editor/Mono/Audio/Mixer/GUI/AudioMixerChannelStripView.cs index fedabc757a..ddf24fc77f 100644 --- a/Editor/Mono/Audio/Mixer/GUI/AudioMixerChannelStripView.cs +++ b/Editor/Mono/Audio/Mixer/GUI/AudioMixerChannelStripView.cs @@ -1298,7 +1298,7 @@ void DoTotaldB(ChannelStripParams p) GUI.Label(rect, string.Format(CultureInfo.InvariantCulture.NumberFormat, "{0:F1} dB", vu_level), styles.totalVULevel); } - GUIContent addText = EditorGUIUtility.TrTextContent("Add.."); + GUIContent addText = EditorGUIUtility.TrTextContent("Add..."); void DoEffectList(ChannelStripParams p, bool selected, ref int highlightEffectIndex, ref Dictionary patchslots, bool showBusConnectionsOfSelection) { Event evt = Event.current; diff --git a/Editor/Mono/Audio/Mixer/GUI/AudioMixerEffectView.cs b/Editor/Mono/Audio/Mixer/GUI/AudioMixerEffectView.cs index d9fefce433..89f6e54a4d 100644 --- a/Editor/Mono/Audio/Mixer/GUI/AudioMixerEffectView.cs +++ b/Editor/Mono/Audio/Mixer/GUI/AudioMixerEffectView.cs @@ -283,11 +283,11 @@ public void DoEffectGUI(int effectIndex, AudioMixerGroupController group, List referencingAssemblies = new List(); // determine whether there is an assembly that is referencing the assembly path @@ -571,6 +571,6 @@ internal static string[] GetReferencingPlayerAssembliesForDLL(string dllPath) return referencingAssemblies.ToArray(); } - internal static extern string[] GetManagedPlayerDllPaths(); + internal static extern string[] GetManagedPlayerDllPaths(string assembliesOutputPath); } } diff --git a/Editor/Mono/BuildPipeline/AssemblyStripper.cs b/Editor/Mono/BuildPipeline/AssemblyStripper.cs index f9c067e66f..45c031c7ec 100644 --- a/Editor/Mono/BuildPipeline/AssemblyStripper.cs +++ b/Editor/Mono/BuildPipeline/AssemblyStripper.cs @@ -118,7 +118,7 @@ private static bool StripAssembliesTo(string[] assemblies, string[] searchDirs, } args.Add($"--platform={compilerPlatform}"); - if (platformProvider.target != BuildTarget.Android) + if (!string.IsNullOrEmpty(compilerArchitecture)) args.Add($"--architecture={compilerArchitecture}"); } @@ -631,8 +631,11 @@ private static string GetMethodPreserveBlacklistContents(RuntimeClassRegistry rc return sb.ToString(); } - static public void InvokeFromBuildPlayer(BuildTarget buildTarget, RuntimeClassRegistry usedClasses, ManagedStrippingLevel managedStrippingLevel, BuildReport report) + static public void StripForMonoBackend(BuildTarget buildTarget, RuntimeClassRegistry usedClasses, ManagedStrippingLevel managedStrippingLevel, BuildReport report) { + if (managedStrippingLevel == ManagedStrippingLevel.Disabled) + return; + var stagingAreaData = Paths.Combine("Temp", "StagingArea", "Data"); var platformProvider = new BaseIl2CppPlatformProvider(buildTarget, Path.Combine(stagingAreaData, "Libraries"), report); diff --git a/Editor/Mono/BuildPipeline/DesktopStandalonePostProcessor.cs b/Editor/Mono/BuildPipeline/DesktopStandalonePostProcessor.cs index 48f8b19eb1..ca1bcc7708 100644 --- a/Editor/Mono/BuildPipeline/DesktopStandalonePostProcessor.cs +++ b/Editor/Mono/BuildPipeline/DesktopStandalonePostProcessor.cs @@ -79,6 +79,8 @@ public override void UpdateBootConfig(BuildTarget target, BootConfigData config, if (PlayerSettings.forceSingleInstance) config.AddKey("single-instance"); + if (!PlayerSettings.useFlipModelSwapchain) + config.AddKey("force-d3d11-bltblt-mode"); if (IL2CPPUtils.UseIl2CppCodegenWithMonoBackend(BuildPipeline.GetBuildTargetGroup(target))) config.Set("mono-codegen", "il2cpp"); if ((options & BuildOptions.EnableHeadlessMode) != 0) @@ -173,7 +175,8 @@ private void CopyNativePlugins(BuildPostProcessArgs args, out List cppPl if (isDirectory) { - FileUtil.CopyDirectoryRecursive(imp.assetPath, finalDestinationPath); + // Since we may be copying from Assets make sure to not include .meta files to the build + FileUtil.CopyDirectoryRecursive(imp.assetPath, finalDestinationPath, overwrite: false, ignoreMeta: true); } else { @@ -252,6 +255,12 @@ private void SetupStagingArea(BuildPostProcessArgs args, HashSet filesTo ProcessIl2CppOutputForBinary(args); } } + else + { + var buildTargetGroup = BuildPipeline.GetBuildTargetGroup(args.target); + var managedStrippingLevel = PlayerSettings.GetManagedStrippingLevel(buildTargetGroup); + AssemblyStripper.StripForMonoBackend(args.target, args.usedClassRegistry, managedStrippingLevel, args.report); + } RenameFilesInStagingArea(args); } @@ -280,8 +289,13 @@ private void ProcessIl2CppOutputForBinary(BuildPostProcessArgs args) var dataBackupFolder = Path.Combine(args.stagingArea, GetIl2CppDataBackupFolderName(args)); FileUtil.CreateOrCleanDirectory(dataBackupFolder); + var il2cppOutputFolder = Path.Combine(args.stagingAreaData, "il2cppOutput"); + + // Delete duplicate il2cpp_data that was created in il2cppOutput directory (case 1198179) + FileUtil.DeleteFileOrDirectory(Path.Combine(il2cppOutputFolder, "Data")); + // Move generated C++ code out of Data directory - FileUtil.MoveFileOrDirectory(Path.Combine(args.stagingAreaData, "il2cppOutput"), Path.Combine(dataBackupFolder, "il2cppOutput")); + FileUtil.MoveFileOrDirectory(il2cppOutputFolder, Path.Combine(dataBackupFolder, "il2cppOutput")); if (IL2CPPUtils.UseIl2CppCodegenWithMonoBackend(BuildPipeline.GetBuildTargetGroup(args.target))) { diff --git a/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs b/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs index 4af0a4b267..a085bd6e82 100644 --- a/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs +++ b/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs @@ -365,9 +365,14 @@ public void RunCompileAndLink() var compilerConfiguration = PlayerSettings.GetIl2CppCompilerConfiguration(buildTargetGroup); var arguments = Il2CppNativeCodeBuilderUtils.AddBuilderArguments(il2CppNativeCodeBuilder, OutputFileRelativePath(), m_PlatformProvider.includePaths, m_PlatformProvider.libraryPaths, compilerConfiguration).ToList(); + var additionalArgs = IL2CPPUtils.GetAdditionalArguments(); + if (!string.IsNullOrEmpty(additionalArgs)) + arguments.Add(additionalArgs); + arguments.Add($"--map-file-parser={CommandLineFormatter.PrepareFileName(GetMapFileParserPath())}"); arguments.Add($"--generatedcppdir={CommandLineFormatter.PrepareFileName(Path.GetFullPath(GetCppOutputDirectoryInStagingArea()))}"); arguments.Add(string.Format("--dotnetprofile=\"{0}\"", IL2CPPUtils.ApiCompatibilityLevelToDotNetProfileArgument(PlayerSettings.GetApiCompatibilityLevel(buildTargetGroup)))); + arguments.AddRange(IL2CPPUtils.GetDebuggerIL2CPPArguments(m_PlatformProvider, buildTargetGroup)); Action setupStartInfo = il2CppNativeCodeBuilder.SetupStartInfo; var managedDir = Path.GetFullPath(Path.Combine(m_StagingAreaData, "Managed")); @@ -423,9 +428,7 @@ private void ConvertPlayerDlltoCpp(string inputDirectory, string outputDirectory arguments.Add("--mono-runtime"); // Working around gcc bug 41091 - if (m_PlatformProvider.target == BuildTarget.StandaloneLinux || - m_PlatformProvider.target == BuildTarget.StandaloneLinux64 || - m_PlatformProvider.target == BuildTarget.StandaloneLinuxUniversal) + if (m_PlatformProvider.target == BuildTarget.StandaloneLinux64) { arguments.Add("--disable-aggressive-inlining"); } diff --git a/Editor/Mono/BuildPlayerWindow.cs b/Editor/Mono/BuildPlayerWindow.cs index f7967bed89..4302dc3fab 100644 --- a/Editor/Mono/BuildPlayerWindow.cs +++ b/Editor/Mono/BuildPlayerWindow.cs @@ -26,8 +26,8 @@ public partial class BuildPlayerWindow : EditorWindow { class Styles { - public GUIContent invalidColorSpaceMessage = EditorGUIUtility.TrTextContent("In order to build a player go to 'Player Settings...' to resolve the incompatibility between the Color Space and the current settings.", EditorGUIUtility.GetHelpIcon(MessageType.Warning)); - public GUIContent invalidLightmapEncodingMessage = EditorGUIUtility.TrTextContent("In order to build a player go to 'Player Settings...' to resolve the incompatibility between the selected Lightmap Encoding and the current settings.", EditorGUIUtility.GetHelpIcon(MessageType.Warning)); + public GUIContent invalidColorSpaceMessage = EditorGUIUtility.TrTextContent("In order to build a player, go to 'Player Settings...' to resolve the incompatibility between the Color Space and the current settings.", EditorGUIUtility.GetHelpIcon(MessageType.Warning)); + public GUIContent invalidLightmapEncodingMessage = EditorGUIUtility.TrTextContent("In order to build a player, go to 'Player Settings...' to resolve the incompatibility between the selected Lightmap Encoding and the current settings.", EditorGUIUtility.GetHelpIcon(MessageType.Warning)); public GUIStyle selected = "OL SelectedRow"; public GUIStyle box = "OL Box"; public GUIStyle title = EditorStyles.boldLabel; @@ -784,9 +784,6 @@ void ShowBuildTargetSettings() GUILayout.EndHorizontal(); } - if (buildTarget == BuildTarget.Android) - AndroidPublishGUI(); - GUIBuildButtons(buildWindowExtension, enableBuildButton, enableBuildAndRunButton, canInstallInBuildFolder, platform); } diff --git a/Editor/Mono/BuildPlayerWindowPublish.cs b/Editor/Mono/BuildPlayerWindowPublish.cs deleted file mode 100644 index 235224fb24..0000000000 --- a/Editor/Mono/BuildPlayerWindowPublish.cs +++ /dev/null @@ -1,327 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEditor.PackageManager; -using UnityEditor.PackageManager.Requests; - -namespace UnityEditor -{ - public partial class BuildPlayerWindow : EditorWindow - { - private struct RequestQueueItem - { - public Request Request; - public PackmanOperationType OperationType; - - public RequestQueueItem(Request r, PackmanOperationType type) - { - Request = r; - OperationType = type; - } - } - - enum PackmanOperationType : uint - { - None = 0, - List, - Add, - Remove, - Search, - Outdated - } - - private bool IsVersionInitialized - { - get { return currentVersionInitialized && latestVersionInitialized; } - } - - private bool currentVersionInitialized = false; - private bool latestVersionInitialized = false; - private bool xiaomiPackageInstalled = false; - private bool packmanOperationRunning = false; - private string xiaomiPackageName = "com.unity.xiaomi"; - private string currentXiaomiPackageVersion = ""; - private string latestXiaomiPackageVersion = ""; - - private List requestList = new List(); - - private bool requestingCurrentPackage = false; - private bool requestingLatestPackage = false; - - string CurrentXiaomiPackageId - { - get - { - return xiaomiPackageName + "@" + currentXiaomiPackageVersion; - } - } - - string LatestXiaomiPackageId - { - get - { - return xiaomiPackageName + "@" + latestXiaomiPackageVersion; - } - } - - class PublishStyles - { - public const int kIconSize = 32; - public const int kRowHeight = 36; - public GUIContent xiaomiIcon = EditorGUIUtility.IconContent("BuildSettings.Xiaomi"); - public GUIContent learnAboutXiaomiInstallation = EditorGUIUtility.TextContent("Installation and Setup"); - public GUIContent publishTitle = EditorGUIUtility.TextContent("SDKs for App Stores|Integrations with 3rd party app stores"); - } - private PublishStyles publishStyles = null; - - private void AndroidPublishGUI() - { - if (publishStyles == null) - publishStyles = new PublishStyles(); - - GUILayout.BeginVertical(); - GUILayout.Label(publishStyles.publishTitle, styles.title); - - // Show Xiaomi UI. - using (new EditorGUILayout.HorizontalScope(styles.box, new GUILayoutOption[] { GUILayout.Height(PublishStyles.kRowHeight) })) - { - GUILayout.BeginVertical(); - GUILayout.Space(3); // fix top padding for box style - - GUILayout.BeginHorizontal(); - GUILayout.Space(4); // left padding - - // icon - GUILayout.BeginVertical(); - GUILayout.Space((PublishStyles.kRowHeight - PublishStyles.kIconSize) / 2); - GUILayout.Label(publishStyles.xiaomiIcon, new GUILayoutOption[] { GUILayout.Width(PublishStyles.kIconSize), GUILayout.Height(PublishStyles.kIconSize) }); - GUILayout.EndVertical(); - - // label - GUILayout.BeginVertical(); - GUILayout.FlexibleSpace(); - GUILayout.Label("Xiaomi Mi Game Center"); - GUILayout.FlexibleSpace(); - GUILayout.EndVertical(); - - // link - GUILayout.FlexibleSpace(); // right justify text - GUILayout.BeginVertical(); - GUILayout.FlexibleSpace(); - XiaomiPackageControlGUI(); - GUILayout.FlexibleSpace(); - GUILayout.EndVertical(); - - GUILayout.Space(4); // right padding - GUILayout.EndHorizontal(); - - GUILayout.EndVertical(); - } - - GUILayout.EndVertical(); - } - - private void XiaomiPackageControlGUI() - { - EditorGUI.BeginDisabledGroup(!IsVersionInitialized || packmanOperationRunning); - - if (!xiaomiPackageInstalled) - { - if (GUILayout.Button("Add", GUILayout.Width(60))) - { - if (packmanOperationRunning) - return; - - AddRequest add = Client.Add(LatestXiaomiPackageId); - requestList.Add(new RequestQueueItem(add, PackmanOperationType.Add)); - System.Console.WriteLine("Adding: " + LatestXiaomiPackageId); - packmanOperationRunning = true; - } - } - else - { - GUILayout.BeginHorizontal(); - if (!string.IsNullOrEmpty(latestXiaomiPackageVersion) && currentXiaomiPackageVersion != latestXiaomiPackageVersion) - { - if (GUILayout.Button("Update", GUILayout.Width(60))) - { - if (packmanOperationRunning) - return; - - if (EditorUtility.DisplayDialog("Update Xiaomi SDK", "Are you sure you want to update to " + latestXiaomiPackageVersion + " ?", "Yes", "No")) - { - AddRequest add = Client.Add(LatestXiaomiPackageId); - requestList.Add(new RequestQueueItem(add, PackmanOperationType.Add)); - System.Console.WriteLine("Updating to: " + LatestXiaomiPackageId); - packmanOperationRunning = true; - } - } - } - if (GUILayout.Button("Remove", GUILayout.Width(60))) - { - if (packmanOperationRunning) - return; - - RemoveRequest remove = Client.Remove(xiaomiPackageName); - requestList.Add(new RequestQueueItem(remove, PackmanOperationType.Remove)); - System.Console.WriteLine("Removing Xiaomi Package: " + CurrentXiaomiPackageId); - packmanOperationRunning = true; - } - GUILayout.EndHorizontal(); - } - - EditorGUI.EndDisabledGroup(); - } - - void CheckXiaomiPackageVersions() - { - if (IsVersionInitialized) - return; - - if (string.IsNullOrEmpty(currentXiaomiPackageVersion) && !requestingCurrentPackage) - { - requestList.Add(new RequestQueueItem(Client.List(), PackmanOperationType.List)); - packmanOperationRunning = requestingCurrentPackage = true; - } - - if (string.IsNullOrEmpty(latestXiaomiPackageVersion) && !requestingLatestPackage) - { - requestList.Add(new RequestQueueItem(Client.Search(xiaomiPackageName), PackmanOperationType.Search)); - packmanOperationRunning = requestingLatestPackage = true; - } - } - - void Update() - { - //Initialization - CheckXiaomiPackageVersions(); - - if (!packmanOperationRunning) - return; - - packmanOperationRunning = !CheckPackmanOperation(); - } - - bool CheckPackmanOperation() - { - if (requestList.Count == 0) - return true; - - RequestQueueItem requestItem = requestList[0]; - StatusCode statusCode = requestItem.Request.Status; - - if (statusCode == StatusCode.Failure) - { - Error error = requestItem.Request.Error; - Debug.LogError("Operation " + requestItem.Request + " failed with Error: " + error); - return true; - } - else if (statusCode == StatusCode.InProgress) - { - return false; - } - else if (statusCode == StatusCode.Success) - { - System.Console.WriteLine("Operation " + requestItem.Request + " Done"); - switch (requestItem.OperationType) - { - case PackmanOperationType.List: - ExtractCurrentXiaomiPackageInfo(requestItem); - break; - case PackmanOperationType.Add: - PerformAdd(requestItem); - break; - case PackmanOperationType.Remove: - PerformRemove(requestItem.Request.Status); - break; - case PackmanOperationType.Search: - ExtractLatestXiaomiPackageInfo(requestItem); - break; - default: - System.Console.WriteLine("Type " + requestItem.OperationType + " Not Supported"); - break; - } - requestList.RemoveAt(0); - if (requestList.Count > 0) - return false; - else - return true; - } - return false; - } - - void PerformAdd(RequestQueueItem request) - { - currentXiaomiPackageVersion = latestXiaomiPackageVersion = ((AddRequest)request.Request).Result.version; - if (request.Request.Status == StatusCode.Failure) - { - Debug.LogError("Adding/Updating to " + latestXiaomiPackageVersion + " resulted in error, please add it again."); - return; - } - xiaomiPackageInstalled = true; - } - - void PerformRemove(StatusCode status) - { - if (status == StatusCode.Failure) - { - Debug.LogError("Remove " + currentXiaomiPackageVersion + " error, please remove it again."); - return; - } - else if (status == StatusCode.Success) - { - currentXiaomiPackageVersion = null; - xiaomiPackageInstalled = false; - } - } - - void ExtractCurrentXiaomiPackageInfo(RequestQueueItem request) - { - ListRequest currentPackageListRequest = (ListRequest)request.Request; - if (currentPackageListRequest.Status == StatusCode.Success) - { - System.Console.WriteLine("Current xiaomi package version is " + - (string.IsNullOrEmpty(currentXiaomiPackageVersion) - ? "empty" - : currentXiaomiPackageVersion)); - - if (currentPackageListRequest.IsCompleted && string.IsNullOrEmpty(currentXiaomiPackageVersion)) - { - PackageManager.PackageInfo info = currentPackageListRequest.Result.FirstOrDefault(p => p.name == xiaomiPackageName); - if (info != null) - currentXiaomiPackageVersion = info.version; - if (!string.IsNullOrEmpty(currentXiaomiPackageVersion)) - xiaomiPackageInstalled = true; - } - currentVersionInitialized = true; - } - else - System.Console.WriteLine(currentPackageListRequest + " failed with error: " + - currentPackageListRequest.Error); - } - - void ExtractLatestXiaomiPackageInfo(RequestQueueItem request) - { - SearchRequest latestPackageSearchRequest = (SearchRequest)request.Request; - if (latestPackageSearchRequest.Status == StatusCode.Success) - { - System.Console.WriteLine("Latest xiaomi package version is " + - (string.IsNullOrEmpty(latestXiaomiPackageVersion) - ? "empty" - : latestXiaomiPackageVersion)); - - if (latestPackageSearchRequest.IsCompleted && latestPackageSearchRequest.Result.Length > 0 && - string.IsNullOrEmpty(latestXiaomiPackageVersion)) - latestXiaomiPackageVersion = latestPackageSearchRequest.Result[0].version; - latestVersionInitialized = true; - } - else - System.Console.WriteLine(latestPackageSearchRequest + " failed with error: " + - latestPackageSearchRequest.Error); - } - } -} diff --git a/Editor/Mono/BuildTarget.cs b/Editor/Mono/BuildTarget.cs index 07c376ee8f..fd26ad5873 100644 --- a/Editor/Mono/BuildTarget.cs +++ b/Editor/Mono/BuildTarget.cs @@ -53,8 +53,7 @@ public enum BuildTarget // was NaCl = 16, // Build a Linux standalone (i386 only). - // TODO: Uncomment this attribute once HDRP plugin is updated in 2019.2. - // [System.Obsolete("StandaloneLinux has been removed in 2019.2")] + [System.Obsolete("StandaloneLinux has been removed in 2019.2")] StandaloneLinux = 17, // Build a Windows x86_64 standalone. @@ -70,8 +69,7 @@ public enum BuildTarget StandaloneLinux64 = 24, // Build a Linux standalone (i386/x86_64 universal). - // TODO: Uncomment this attribute once HDRP plugin is updated in 2019.2. - // [System.Obsolete("StandaloneLinuxUniversal has been removed in 2019.2")] + [System.Obsolete("StandaloneLinuxUniversal has been removed in 2019.2")] StandaloneLinuxUniversal = 25, [System.Obsolete("Use WSAPlayer with Windows Phone 8.1 selected")] diff --git a/Editor/Mono/CodeEditor/CodeEditor.cs b/Editor/Mono/CodeEditor/CodeEditor.cs new file mode 100644 index 0000000000..83628e4db9 --- /dev/null +++ b/Editor/Mono/CodeEditor/CodeEditor.cs @@ -0,0 +1,217 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using UnityEditor; +using UnityEditor.Callbacks; +using UnityEditorInternal; +using UnityEngine; +using UnityEngine.Scripting; + +namespace Unity.CodeEditor +{ + public class CodeEditor + { + internal static CodeEditor Editor { get; } = new CodeEditor(); + List m_ExternalCodeEditors = new List(); + IExternalCodeEditor m_DefaultEditor = new DefaultExternalCodeEditor(); + internal const string SystemDefaultPath = ""; + + public struct Installation + { + public string Name; + public string Path; + } + + [RequiredByNativeCode] + static bool OpenProject(string path, int line, int column) + { + return Editor.Current.OpenProject(path, line, column); + } + + [OnOpenAsset] + static bool OnOpenAsset(int instanceID, int line, int column) + { + var selected = EditorUtility.InstanceIDToObject(instanceID); + var assetPath = AssetDatabase.GetAssetPath(selected); + + #pragma warning disable 618 + if (ScriptEditorUtility.GetScriptEditorFromPath(CurrentEditorInstallation) != ScriptEditorUtility.ScriptEditor.Other) + { + return false; + } + + if (string.IsNullOrEmpty(assetPath)) + { + return false; + } + + var assetFilePath = Path.GetFullPath(assetPath); + return Editor.Current.OpenProject(assetFilePath, line, column); + } + + internal Installation EditorInstallation + { + get + { + var editorPath = CurrentEditorInstallation.Trim(); + if (editorPath == CodeEditor.SystemDefaultPath) + { + // If no script editor is set, try to use first found supported one. + var editorPaths = GetFoundScriptEditorPaths(); + if (editorPaths.Count > 0) + { + return new Installation { Path = editorPaths.Keys.First() }; + } + + return new Installation + { + Name = "Internal", + Path = editorPath, + }; + } + + foreach (var codeEditor in m_ExternalCodeEditors) + { + Installation installation; + if (codeEditor.TryGetInstallationForPath(editorPath, out installation)) + { + return installation; + } + } + + return new Installation { Path = editorPath }; + } + } + + internal IExternalCodeEditor Current + { + get + { + var editorPath = CurrentEditorInstallation.Trim(); + if (editorPath == CodeEditor.SystemDefaultPath) + { + return m_DefaultEditor; + } + + foreach (var codeEditor in m_ExternalCodeEditors) + { + Installation installation; + if (codeEditor.TryGetInstallationForPath(editorPath, out installation)) + { + return codeEditor; + } + } + + return m_DefaultEditor; + } + } + + internal Dictionary GetFoundScriptEditorPaths() + { + var result = new Dictionary(); + + foreach (var installation in m_ExternalCodeEditors.SelectMany(codeEditor => codeEditor.Installations)) + { + AddIfPathExists(installation.Name, installation.Path, result); + } + + return result; + } + + internal static void AddIfPathExists(string name, string path, Dictionary list) + { + if (list.ContainsKey(path)) + return; + if (Directory.Exists(path)) list.Add(path, name); + else if (File.Exists(path)) list.Add(path, name); + } + + public static void SetExternalScriptEditor(string path) + { + EditorPrefs.SetString("kScriptsDefaultApp", path); + Editor.Current.Initialize(path); + } + + public static void Register(IExternalCodeEditor externalCodeEditor) + { + Editor.m_ExternalCodeEditors.Add(externalCodeEditor); + } + + public static void Unregister(IExternalCodeEditor externalCodeEditor) + { + Editor.m_ExternalCodeEditors.Remove(externalCodeEditor); + } + + public static IExternalCodeEditor CurrentEditor => Editor.Current; + + public static string CurrentEditorInstallation => EditorPrefs.GetString("kScriptsDefaultApp"); + + public static bool OSOpenFile(string appPath, string arguments) + { + return ExternalEditor.OSOpenFileWithArgument(appPath, arguments); + } + + public static string ParseArgument(string arguments, string path, int line, int column) + { + var newArgument = arguments.Replace("$(ProjectPath)", QuoteForProcessStart(Directory.GetParent(Application.dataPath).FullName)); + newArgument = newArgument.Replace("$(File)", QuoteForProcessStart(path)); + newArgument = newArgument.Replace("$(Line)", line >= 0 ? line.ToString() : "0"); + newArgument = newArgument.Replace("$(Column)", column >= 0 ? column.ToString() : "0"); + return newArgument; + } + + /// + /// Quote a string for passing as a single argument to Process.Start + /// and append it to this string builder. + /// + /// + /// On Windows, quote according to the Win32 CommandLineToArgvW API scheme, + /// used by most Windows applications (with some notable exceptions, like + /// cmd.exe and cscript.exe). On Unix, Mono uses the entirely incompatible + /// GLib g_shell_parse_argv function for converting the argument string to + /// a native Unix argument list, so quote for that instead. + /// + /// Do not use this to quote arguments for command line shells (cmd.exe + /// or POSIX shell), as these may use distinct quotation mechanisms. + /// + /// Do not append two quoted arguments without an (unquoted) separator + /// between them: Two consecutive quotation marks triggers undocumented + /// behavior in CommandLineToArgvW and possibly other argument processors. + /// + // https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/ + static string QuoteForProcessStart(string argument) + { + var sb = new StringBuilder(); + // Quote for g_shell_parse_argv when running on Unix (under Mono). + if (Application.platform != RuntimePlatform.WindowsEditor) + { + sb.Append('\''); + sb.Append(argument.Replace("\\", "\\\\").Replace("'", "\\'")); + sb.Append('\''); + return sb.ToString(); + } + + sb.Append('"'); + for (int i = 0; i < argument.Length; ++i) + { + char c = argument[i]; + if (c == '"') + { + for (int j = i - 1; j >= 0 && argument[j] == '\\'; --j) + sb.Append('\\'); + sb.Append('\\'); + } + sb.Append(c); + } + for (int j = argument.Length - 1; j >= 0 && argument[j] == '\\'; --j) + sb.Append('\\'); + sb.Append('"'); + return sb.ToString(); + } + } +} diff --git a/Editor/Mono/CodeEditor/CodeEditorProjectSync.cs b/Editor/Mono/CodeEditor/CodeEditorProjectSync.cs new file mode 100644 index 0000000000..f5376fb2b3 --- /dev/null +++ b/Editor/Mono/CodeEditor/CodeEditorProjectSync.cs @@ -0,0 +1,67 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using System; +using Unity.CodeEditor; +using UnityEngine; +using UnityEngine.Scripting; +using UnityEditorInternal; + +namespace UnityEditor +{ + internal class CodeEditorProjectSync : AssetPostprocessor + { + class BuildTargetChangedHandler : Build.IActiveBuildTargetChanged + { + public int callbackOrder => 0; + + public void OnActiveBuildTargetChanged(BuildTarget oldTarget, BuildTarget newTarget) + { + CodeEditor.Editor.Current.SyncAll(); + } + } + + [RequiredByNativeCode] + public static void SyncEditorProject() + { + CodeEditor.Editor.Current.SyncAll(); + } + + // For the time being this doesn't use the callback + public static void PostprocessSyncProject( + string[] importedAssets, + string[] addedAssets, + string[] deletedAssets, + string[] movedAssets, + string[] movedFromAssetPaths) + { + CodeEditor.Editor.Current.SyncIfNeeded(addedAssets, deletedAssets, movedAssets, movedFromAssetPaths, importedAssets); + } + + [MenuItem("Assets/Open C# Project")] + static void SyncAndOpenSolution() + { + // Ensure that the mono islands are up-to-date + AssetDatabase.Refresh(); + CodeEditor.Editor.Current.SyncAll(); + OpenProjectFileUnlessInBatchMode(); + } + + static void OpenProjectFileUnlessInBatchMode() + { + if (InternalEditorUtility.inBatchMode) + return; + + #pragma warning disable 618 + if (ScriptEditorUtility.GetScriptEditorFromPath(CodeEditor.CurrentEditorInstallation) == ScriptEditorUtility.ScriptEditor.Other) + { + CodeEditor.Editor.Current.OpenProject(); + } + else + { + InternalEditorUtility.OpenFileAtLineExternal("", -1, -1); + } + } + } +} diff --git a/Editor/Mono/CodeEditor/DefaultExternalCodeEditor.cs b/Editor/Mono/CodeEditor/DefaultExternalCodeEditor.cs new file mode 100644 index 0000000000..b0c4fdc6bc --- /dev/null +++ b/Editor/Mono/CodeEditor/DefaultExternalCodeEditor.cs @@ -0,0 +1,143 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using Unity.CodeEditor; +using UnityEngine; + +namespace UnityEditor +{ + internal class DefaultExternalCodeEditor : IExternalCodeEditor + { + static readonly GUIContent k_ResetArguments = EditorGUIUtility.TrTextContent("Reset argument"); + static bool IsOSX => Application.platform == RuntimePlatform.OSXEditor; + + string m_ChosenInstallation; + const string k_ArgumentKey = "kScriptEditorArgs"; + const string k_DefaultArgument = "$(File)"; + + string Arguments + { + get + { + // Starting in Unity 5.5, we support setting script editor arguments on OSX and + // use then when opening the script editor. + // Before Unity 5.5, we would still save the default script editor args in EditorPrefs, + // even though we never used them. This means that the user potentially has some + // script editor args saved and once he upgrades to 5.5, they will be used when + // open the script editor. Which unintended and causes a regression in behaviour. + // So on OSX we change the key for per application for script editor args, + // to avoid reading the one from previous versions. + // The year 2021: Delete mac hack. + if (Application.platform == RuntimePlatform.OSXEditor) + { + var oldMac = EditorPrefs.GetString("kScriptEditorArgs_" + m_ChosenInstallation); + if (!string.IsNullOrEmpty(oldMac)) + { + EditorPrefs.SetString(k_ArgumentKey, oldMac); + } + } + + return EditorPrefs.GetString(k_ArgumentKey + m_ChosenInstallation, k_DefaultArgument); + } + set + { + if (Application.platform == RuntimePlatform.OSXEditor) + { + EditorPrefs.SetString("kScriptEditorArgs_" + m_ChosenInstallation, value); + } + + EditorPrefs.SetString(k_ArgumentKey + m_ChosenInstallation, value); + } + } + public CodeEditor.Installation[] Installations { get; } + public bool TryGetInstallationForPath(string editorPath, out CodeEditor.Installation installation) + { + installation = new CodeEditor.Installation + { + Name = Path.GetFileNameWithoutExtension(editorPath), + Path = editorPath + }; + return true; + } + + public void OnGUI() + { + Arguments = EditorGUILayout.TextField("External Script Editor Args", Arguments); + if (GUILayout.Button(k_ResetArguments, GUILayout.Width(120))) + { + Arguments = k_DefaultArgument; + } + } + + public void SyncIfNeeded(string[] addedFiles, string[] deletedFiles, string[] movedFiles, string[] movedFromFiles, string[] importedFiles) + { + } + + public void SyncAll() + { + } + + public void Initialize(string editorInstallationPath) + { + m_ChosenInstallation = editorInstallationPath; + } + + static string[] defaultExtensions + { + get + { + var customExtensions = new[] {"json", "asmdef", "log"}; + return EditorSettings.projectGenerationBuiltinExtensions + .Concat(EditorSettings.projectGenerationUserExtensions) + .Concat(customExtensions) + .Distinct().ToArray(); + } + } + + static bool SupportsExtension(string path) + { + var extension = Path.GetExtension(path); + if (string.IsNullOrEmpty(extension)) + return false; + return defaultExtensions.Contains(extension.TrimStart('.')); + } + + public bool OpenProject(string path, int line, int column) + { + if (path != "" && !SupportsExtension(path)) // Assets - Open C# Project passes empty path here + { + return false; + } + + string applicationPath = CodeEditor.CurrentEditorInstallation.Trim(); + if (applicationPath == CodeEditor.SystemDefaultPath) + { + return false; + } + + if (IsOSX) + { + return CodeEditor.OSOpenFile(applicationPath, CodeEditor.ParseArgument(Arguments, path, line, column)); + } + + var process = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = applicationPath, + Arguments = CodeEditor.ParseArgument(Arguments, path, line, column), + WindowStyle = ProcessWindowStyle.Hidden, + CreateNoWindow = true, + UseShellExecute = true, + } + }; + var result = process.Start(); + return result; + } + } +} diff --git a/Editor/Mono/CodeEditor/ExternalEditor.bindings.cs b/Editor/Mono/CodeEditor/ExternalEditor.bindings.cs new file mode 100644 index 0000000000..4e94506f0d --- /dev/null +++ b/Editor/Mono/CodeEditor/ExternalEditor.bindings.cs @@ -0,0 +1,15 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using UnityEngine.Bindings; + +namespace Unity.CodeEditor +{ + [NativeHeader("Editor/Platform/Interface/ExternalEditor.h")] + internal class ExternalEditor + { + [FreeFunction("PlatformSpecificOpenFileAtLine")] + internal static extern bool OSOpenFileWithArgument(string appPath, string arguments); + } +} diff --git a/Editor/Mono/CodeEditor/IExternalCodeEditor.cs b/Editor/Mono/CodeEditor/IExternalCodeEditor.cs new file mode 100644 index 0000000000..3c2090bc8b --- /dev/null +++ b/Editor/Mono/CodeEditor/IExternalCodeEditor.cs @@ -0,0 +1,17 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +namespace Unity.CodeEditor +{ + public interface IExternalCodeEditor + { + CodeEditor.Installation[] Installations { get; } + bool TryGetInstallationForPath(string editorPath, out CodeEditor.Installation installation); + void OnGUI(); + void SyncIfNeeded(string[] addedFiles, string[] deletedFiles, string[] movedFiles, string[] movedFromFiles, string[] importedFiles); + void SyncAll(); + void Initialize(string editorInstallationPath); + bool OpenProject(string filePath = "", int line = -1, int column = -1); + } +} diff --git a/Editor/Mono/CodeEditor/SyncVS.cs b/Editor/Mono/CodeEditor/SyncVS.cs new file mode 100644 index 0000000000..6cefc73066 --- /dev/null +++ b/Editor/Mono/CodeEditor/SyncVS.cs @@ -0,0 +1,70 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using System; +using System.Security.Cryptography; +using System.Text; +using Unity.CodeEditor; +using UnityEditorInternal; + +namespace UnityEditor +{ + partial class SyncVS + { + public static void SyncSolution() + { + // Ensure that the mono islands are up-to-date + AssetDatabase.Refresh(); + + // TODO: Rider and possibly other code editors, use reflection to call this method. + // To avoid conflicts and null reference exception, this is left as a dummy method. + Unity.CodeEditor.CodeEditor.Editor.Current.SyncAll(); + + #pragma warning disable 618 + if (ScriptEditorUtility.GetScriptEditorFromPath(CodeEditor.CurrentEditorInstallation) != ScriptEditorUtility.ScriptEditor.Other) + { + Synchronizer.Sync(); + } + } + } + + namespace VisualStudioIntegration + { + public static class SolutionGuidGenerator + { + public static string GuidForProject(string projectName) + { + return ComputeGuidHashFor(projectName + "salt"); + } + + public static string GuidForSolution(string projectName, string sourceFileExtension) + { + if (sourceFileExtension.ToLower() == "cs") + // GUID for a C# class library: http://www.codeproject.com/Reference/720512/List-of-Visual-Studio-Project-Type-GUIDs + return "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC"; + return ComputeGuidHashFor(projectName); + } + + private static string ComputeGuidHashFor(string input) + { + var hash = MD5.Create().ComputeHash(Encoding.Default.GetBytes(input)); + return HashAsGuid(HashToString(hash)); + } + + private static string HashAsGuid(string hash) + { + var guid = hash.Substring(0, 8) + "-" + hash.Substring(8, 4) + "-" + hash.Substring(12, 4) + "-" + hash.Substring(16, 4) + "-" + hash.Substring(20, 12); + return guid.ToUpper(); + } + + private static string HashToString(byte[] bs) + { + var sb = new StringBuilder(); + foreach (byte b in bs) + sb.Append(b.ToString("x2")); + return sb.ToString(); + } + } + } +} diff --git a/Editor/Mono/ConsoleWindow.cs b/Editor/Mono/ConsoleWindow.cs index 652dd1a495..698638d4a6 100644 --- a/Editor/Mono/ConsoleWindow.cs +++ b/Editor/Mono/ConsoleWindow.cs @@ -730,7 +730,7 @@ private void SearchField(Event e) } } - private static string StacktraceWithHyperlinks(string stacktraceText) + internal static string StacktraceWithHyperlinks(string stacktraceText) { StringBuilder textWithHyperlinks = new StringBuilder(); var lines = stacktraceText.Split(new string[] {"\n"}, StringSplitOptions.None); @@ -747,7 +747,7 @@ private static string StacktraceWithHyperlinks(string stacktraceText) int lineIndex = filePathPart.LastIndexOf(":", StringComparison.Ordinal); // LastIndex because the url can contain ':' ex:"C:" if (lineIndex > 0) { - int endLineIndex = filePathPart.IndexOf(")", StringComparison.Ordinal); + int endLineIndex = filePathPart.LastIndexOf(")", StringComparison.Ordinal); // LastIndex because files or folder in the url can contain ')' if (endLineIndex > 0) { string lineString = @@ -757,7 +757,7 @@ private static string StacktraceWithHyperlinks(string stacktraceText) textWithHyperlinks.Append(lines[i].Substring(0, filePathIndex)); textWithHyperlinks.Append(""); textWithHyperlinks.Append(filePath + ":" + lineString); - textWithHyperlinks.AppendLine(")"); + textWithHyperlinks.Append(")\n"); continue; // continue to evade the default case } @@ -765,8 +765,11 @@ private static string StacktraceWithHyperlinks(string stacktraceText) } } // default case if no hyperlink : we just write the line - textWithHyperlinks.AppendLine(lines[i]); + textWithHyperlinks.Append(lines[i] + "\n"); } + // Remove the last \n + if (textWithHyperlinks.Length > 0) // textWithHyperlinks always ends with \n if it is not empty + textWithHyperlinks.Remove(textWithHyperlinks.Length - 1, 1); return textWithHyperlinks.ToString(); } diff --git a/Editor/Mono/ContainerWindow.cs b/Editor/Mono/ContainerWindow.cs index 7e6a68192e..16c1e125b4 100644 --- a/Editor/Mono/ContainerWindow.cs +++ b/Editor/Mono/ContainerWindow.cs @@ -420,8 +420,12 @@ private bool TitleBarButton(GUIStyle style) } // Snapping windows - static Vector2 s_LastDragMousePos; - float startDragDpi; + private static Vector2 s_LastDragMousePos; + private float startDragDpi; + + // Indicates that we are using the native title bar caption dragging. + private bool m_DraggingNativeTitleBarCaption = false; + private void DragTitleBar(Rect titleBarRect) { int id = GUIUtility.GetControlID(FocusType.Passive); @@ -430,30 +434,33 @@ private void DragTitleBar(Rect titleBarRect) switch (evt.GetTypeForControl(id)) { case EventType.Repaint: + if (m_DraggingNativeTitleBarCaption) + m_DraggingNativeTitleBarCaption = false; EditorGUIUtility.AddCursorRect(titleBarRect, MouseCursor.Arrow); break; case EventType.MouseDown: // If the mouse is inside the title bar rect, we say that we're the hot control if (titleBarRect.Contains(evt.mousePosition) && GUIUtility.hotControl == 0 && evt.button == 0) { - GUIUtility.hotControl = id; - if (Application.platform != RuntimePlatform.WindowsEditor) + if (Application.platform == RuntimePlatform.WindowsEditor) { - s_LastDragMousePos = evt.mousePosition; - startDragDpi = GUIUtility.pixelsPerPoint; + Event.current.Use(); + m_DraggingNativeTitleBarCaption = true; + SendCaptionEvent(m_DraggingNativeTitleBarCaption); } else { - SendCaptionEvent(true); + GUIUtility.hotControl = id; + Event.current.Use(); + s_LastDragMousePos = evt.mousePosition; + startDragDpi = GUIUtility.pixelsPerPoint; + Unsupported.SetAllowCursorLock(false, Unsupported.DisallowCursorLockReasons.SizeMove); } - - Event.current.Use(); - Unsupported.SetAllowCursorLock(false, Unsupported.DisallowCursorLockReasons.SizeMove); } break; case EventType.MouseUp: - if (Application.platform == RuntimePlatform.WindowsEditor) - SendCaptionEvent(false); + if (m_DraggingNativeTitleBarCaption) + break; if (GUIUtility.hotControl == id) { @@ -463,6 +470,9 @@ private void DragTitleBar(Rect titleBarRect) } break; case EventType.MouseDrag: + if (m_DraggingNativeTitleBarCaption) + break; + if (GUIUtility.hotControl == id) { Vector2 mousePos = evt.mousePosition; diff --git a/Editor/Mono/CustomInspectorStubs.cs b/Editor/Mono/CustomInspectorStubs.cs index 824cd94150..8645e8b7e0 100644 --- a/Editor/Mono/CustomInspectorStubs.cs +++ b/Editor/Mono/CustomInspectorStubs.cs @@ -17,6 +17,7 @@ private PhysicsManager() {} // Exposed as internal, editor-only, because we only need it do make a custom inspector [NativeClass(null)] + [ExcludeFromPreset] internal sealed class AudioManager : ProjectSettingsBase { private AudioManager() {} diff --git a/Editor/Mono/DragAndDropService.cs b/Editor/Mono/DragAndDropService.cs index 516fc6a937..2736086c1d 100644 --- a/Editor/Mono/DragAndDropService.cs +++ b/Editor/Mono/DragAndDropService.cs @@ -185,18 +185,20 @@ private static DragAndDropVisualMode DefaultProjectBrowserDrop(int dragUponInsta if (search.Find(dragUponInstanceId, null)) return InternalEditorUtility.ProjectWindowDrag(search, perform); - var path = AssetDatabase.GetAssetPath(dragUponInstanceId); - if (string.IsNullOrEmpty(path)) - return DragAndDropVisualMode.Rejected; - - var packageInfo = PackageManager.PackageInfo.FindForAssetPath(path); - if (packageInfo != null) + if (dragUponInstanceId != 0) { - search = new HierarchyProperty(packageInfo.assetPath); - if (search.Find(dragUponInstanceId, null)) - return InternalEditorUtility.ProjectWindowDrag(search, perform); - } + var path = AssetDatabase.GetAssetPath(dragUponInstanceId); + if (string.IsNullOrEmpty(path)) + return DragAndDropVisualMode.Rejected; + var packageInfo = PackageManager.PackageInfo.FindForAssetPath(path); + if (packageInfo != null) + { + search = new HierarchyProperty(packageInfo.assetPath); + if (search.Find(dragUponInstanceId, null)) + return InternalEditorUtility.ProjectWindowDrag(search, perform); + } + } return InternalEditorUtility.ProjectWindowDrag(null, perform); } diff --git a/Editor/Mono/EditorApplication.cs b/Editor/Mono/EditorApplication.cs index cfcdfa60b5..09d1fba52b 100644 --- a/Editor/Mono/EditorApplication.cs +++ b/Editor/Mono/EditorApplication.cs @@ -10,6 +10,7 @@ using UnityEngine.Events; using UnityEngine.Scripting; using UnityEditorInternal; +using UnityEngine.TestTools; namespace UnityEditor { @@ -37,7 +38,7 @@ public enum PauseState internal class ApplicationTitleDescriptor { - public ApplicationTitleDescriptor(string projectName, string unityVersion, string activeSceneName, string licenseType, bool previewPackageInUse, string targetName) + public ApplicationTitleDescriptor(string projectName, string unityVersion, string activeSceneName, string licenseType, bool previewPackageInUse, string targetName, bool codeCoverageEnabled) { title = ""; this.projectName = projectName; @@ -46,6 +47,7 @@ public ApplicationTitleDescriptor(string projectName, string unityVersion, strin this.licenseType = licenseType; this.previewPackageInUse = previewPackageInUse; this.targetName = targetName; + this.codeCoverageEnabled = codeCoverageEnabled; } public string title; @@ -55,6 +57,7 @@ public ApplicationTitleDescriptor(string projectName, string unityVersion, strin public string licenseType { get; private set; } public bool previewPackageInUse { get; private set; } public string targetName { get; private set; } + public bool codeCoverageEnabled { get; private set; } } public sealed partial class EditorApplication @@ -244,7 +247,7 @@ internal static string GetDefaultMainWindowTitle(ApplicationTitleDescriptor desc ? $"{desc.activeSceneName} - {desc.projectName}" : $"{desc.projectName} - {desc.activeSceneName}"; - // FUTURE: "preview packages in use" and the build target info do not belong in the title bar. they + // FUTURE: [PREVIEW PACKAGES IN USE], [CODE COVERAGE] and the build target info do not belong in the title bar. they // are there now because we want them to be always-visible to user, which normally would be a) buildconfig // bar or b) status bar, but we don't have a) and our b) needs work to support such a thing. @@ -264,6 +267,11 @@ internal static string GetDefaultMainWindowTitle(ApplicationTitleDescriptor desc title += " " + L10n.Tr("[PREVIEW PACKAGES IN USE]"); } + if (desc.codeCoverageEnabled) + { + title += " " + L10n.Tr("[CODE COVERAGE]"); + } + return title; } @@ -282,7 +290,8 @@ internal static string BuildMainWindowTitle() activeSceneName, GetLicenseType(), isPreviewPackageInUse, - BuildPipeline.GetBuildTargetGroupDisplayName(BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget)) + BuildPipeline.GetBuildTargetGroupDisplayName(BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget)), + Coverage.enabled ); desc.title = GetDefaultMainWindowTitle(desc); diff --git a/Editor/Mono/EditorGUI.EnumMaskField.deprecated.cs b/Editor/Mono/EditorGUI.EnumMaskField.deprecated.cs index 62abcbfe63..df06043570 100644 --- a/Editor/Mono/EditorGUI.EnumMaskField.deprecated.cs +++ b/Editor/Mono/EditorGUI.EnumMaskField.deprecated.cs @@ -397,7 +397,7 @@ internal static int DoMaskField(Rect position, int controlID, int mask, string[] mask = ~0; } else - buttonContent = EditorGUIUtility.TempContent("Mixed ..."); + buttonContent = EditorGUIUtility.TempContent("Mixed..."); break; } } diff --git a/Editor/Mono/EditorGUI.cs b/Editor/Mono/EditorGUI.cs index 10237b845b..45414d79f2 100644 --- a/Editor/Mono/EditorGUI.cs +++ b/Editor/Mono/EditorGUI.cs @@ -2406,7 +2406,7 @@ internal static GenericMenu FillPropertyContextMenu(SerializedProperty property, info.properties = properties; info.assetPath = AssetDatabase.GetAssetPath(sourceObject); GameObject rootObject = PrefabUtility.GetRootGameObject(sourceObject); - if (!PrefabUtility.IsPartOfPrefabThatCanBeAppliedTo(rootObject)) + if (!PrefabUtility.IsPartOfPrefabThatCanBeAppliedTo(rootObject) || EditorUtility.IsPersistent(targetObject)) pm.AddDisabledItem(menuItemContent); else pm.AddItem(menuItemContent, false, TargetChoiceHandler.ApplyPrefabPropertyOverride, info); @@ -2926,49 +2926,52 @@ internal static void IntPopupInternal(Rect position, SerializedProperty property internal static void SortingLayerField(Rect position, GUIContent label, SerializedProperty layerID, GUIStyle style, GUIStyle labelStyle) { - int id = GUIUtility.GetControlID(s_SortingLayerFieldHash, FocusType.Keyboard, position); - position = PrefixLabel(position, id, label, labelStyle); - - Event evt = Event.current; - int selected = PopupCallbackInfo.GetSelectedValueForControl(id, -1); - if (selected != -1) + using (new PropertyScope(position, null, layerID)) { - int[] layerIDs = InternalEditorUtility.sortingLayerUniqueIDs; - if (selected >= layerIDs.Length) + int id = GUIUtility.GetControlID(s_SortingLayerFieldHash, FocusType.Keyboard, position); + position = PrefixLabel(position, id, label, labelStyle); + + Event evt = Event.current; + int selected = PopupCallbackInfo.GetSelectedValueForControl(id, -1); + if (selected != -1) { - TagManagerInspector.ShowWithInitialExpansion(TagManagerInspector.InitialExpansionState.SortingLayers); + int[] layerIDs = InternalEditorUtility.sortingLayerUniqueIDs; + if (selected >= layerIDs.Length) + { + TagManagerInspector.ShowWithInitialExpansion(TagManagerInspector.InitialExpansionState.SortingLayers); + } + else + { + layerID.intValue = layerIDs[selected]; + } } - else + + if (evt.type == EventType.MouseDown && position.Contains(evt.mousePosition) || evt.MainActionKeyForControl(id)) { - layerID.intValue = layerIDs[selected]; - } - } + int i = 0; + int[] layerIDs = InternalEditorUtility.sortingLayerUniqueIDs; + string[] layerNames = InternalEditorUtility.sortingLayerNames; + for (i = 0; i < layerIDs.Length; i++) + { + if (layerIDs[i] == layerID.intValue) + break; + } + ArrayUtility.Add(ref layerNames, ""); + ArrayUtility.Add(ref layerNames, "Add Sorting Layer..."); - if (evt.type == EventType.MouseDown && position.Contains(evt.mousePosition) || evt.MainActionKeyForControl(id)) - { - int i = 0; - int[] layerIDs = InternalEditorUtility.sortingLayerUniqueIDs; - string[] layerNames = InternalEditorUtility.sortingLayerNames; - for (i = 0; i < layerIDs.Length; i++) + DoPopup(position, id, i, EditorGUIUtility.TempContent(layerNames), style); + } + else if (Event.current.type == EventType.Repaint) { - if (layerIDs[i] == layerID.intValue) - break; + var layerName = layerID.hasMultipleDifferentValues ? + mixedValueContent : + EditorGUIUtility.TempContent(InternalEditorUtility.GetSortingLayerNameFromUniqueID(layerID.intValue)); + showMixedValue = layerID.hasMultipleDifferentValues; + BeginHandleMixedValueContentColor(); + style.Draw(position, layerName, id, false); + EndHandleMixedValueContentColor(); + showMixedValue = false; } - ArrayUtility.Add(ref layerNames, ""); - ArrayUtility.Add(ref layerNames, "Add Sorting Layer..."); - - DoPopup(position, id, i, EditorGUIUtility.TempContent(layerNames), style); - } - else if (Event.current.type == EventType.Repaint) - { - var layerName = layerID.hasMultipleDifferentValues ? - mixedValueContent : - EditorGUIUtility.TempContent(InternalEditorUtility.GetSortingLayerNameFromUniqueID(layerID.intValue)); - showMixedValue = layerID.hasMultipleDifferentValues; - BeginHandleMixedValueContentColor(); - style.Draw(position, layerName, id, false); - EndHandleMixedValueContentColor(); - showMixedValue = false; } } @@ -5056,16 +5059,20 @@ internal static void RemovedComponentTitlebar(Rect position, GameObject instance GenericMenu menu = new GenericMenu(); PrefabUtility.HandleApplyRevertMenuItems( "Removed Component", - sourceComponent, + instanceGo, (menuItemContent, sourceObject) => { TargetChoiceHandler.ObjectInstanceAndSourceInfo info = new TargetChoiceHandler.ObjectInstanceAndSourceInfo(); info.instanceObject = instanceGo; Component componentToRemove = sourceComponent; - while (componentToRemove != sourceObject) + while (componentToRemove.gameObject != sourceObject) + { componentToRemove = PrefabUtility.GetCorrespondingObjectFromSource(componentToRemove); + if (componentToRemove == null) + return; + } info.correspondingObjectInSource = componentToRemove; - if (!PrefabUtility.IsPartOfPrefabThatCanBeAppliedTo(componentToRemove)) + if (!PrefabUtility.IsPartOfPrefabThatCanBeAppliedTo(componentToRemove) || EditorUtility.IsPersistent(instanceGo)) menu.AddDisabledItem(menuItemContent); else menu.AddItem(menuItemContent, false, TargetChoiceHandler.ApplyPrefabRemovedComponent, info); @@ -9428,6 +9435,9 @@ public static bool BeginFadeGroup(float value) g.guiColor = GUI.color; g.consideredForMargin = value > 0; + // We don't want the fade group gui clip to be used for calculating the label width of controls in this fade group, so we lock the context width. + EditorGUIUtility.LockContextWidth(); + if (value != 0.0f && value != 1.0f) { g.resetCoords = true; @@ -9439,9 +9449,6 @@ public static bool BeginFadeGroup(float value) } } - // We don't want the fade group gui clip to be used for calculating the label width of controls in this fade group, so we lock the context width. - EditorGUIUtility.LockContextWidth(); - return value != 0; } diff --git a/Editor/Mono/EditorGUIUtility.cs b/Editor/Mono/EditorGUIUtility.cs index d651aede68..1ba0d74b85 100644 --- a/Editor/Mono/EditorGUIUtility.cs +++ b/Editor/Mono/EditorGUIUtility.cs @@ -48,7 +48,7 @@ internal static Material GUITextureBlit2SRGBMaterial if (!s_GUITextureBlit2SRGBMaterial) { Shader shader = LoadRequired("SceneView/GUITextureBlit2SRGB.shader") as Shader; - s_GUITextureBlit2SRGBMaterial = new Material(shader) {hideFlags = HideFlags.HideAndDontSave}; + s_GUITextureBlit2SRGBMaterial = new Material(shader); } s_GUITextureBlit2SRGBMaterial.SetFloat("_ManualTex2SRGB", QualitySettings.activeColorSpace == ColorSpace.Linear ? 1.0f : 0.0f); return s_GUITextureBlit2SRGBMaterial; @@ -63,7 +63,7 @@ internal static Material GUITextureBlitSceneGUIMaterial if (!s_GUITextureBlitSceneGUI) { Shader shader = LoadRequired("SceneView/GUITextureBlitSceneGUI.shader") as Shader; - s_GUITextureBlitSceneGUI = new Material(shader) { hideFlags = HideFlags.HideAndDontSave }; + s_GUITextureBlitSceneGUI = new Material(shader); } return s_GUITextureBlitSceneGUI; } @@ -109,7 +109,7 @@ internal static void RepaintCurrentWindow() internal static bool HasCurrentWindowKeyFocus() { CheckOnGUI(); - return GUIView.current != null ? GUIView.current.hasFocus : false; + return GUIView.current != null && GUIView.current.hasFocus; } public static Rect PointsToPixels(Rect rect) @@ -1091,7 +1091,7 @@ internal static float contextWidth } } - public static float currentViewWidth => GUIView.current.position.width; + public static float currentViewWidth => GUIView.current ? GUIView.current.position.width : 0; public static float labelWidth { @@ -1453,7 +1453,7 @@ public static void ShowObjectPicker(UnityObject obj, bool allowSceneObjects, { Type objType = typeof(T); //case 1113046: Delay the show method when it is called while other object picker is closing - if (Event.current.commandName == "ObjectSelectorClosed") + if (Event.current?.commandName == "ObjectSelectorClosed") EditorApplication.delayCall += () => SetupObjectSelector(obj, objType, allowSceneObjects, searchFilter, controlID); else SetupObjectSelector(obj, objType, allowSceneObjects, searchFilter, controlID); diff --git a/Editor/Mono/EditorHandles/BoundsHandle/PrimitiveBoundsHandle.cs b/Editor/Mono/EditorHandles/BoundsHandle/PrimitiveBoundsHandle.cs index 698029d481..075a3b1b07 100644 --- a/Editor/Mono/EditorHandles/BoundsHandle/PrimitiveBoundsHandle.cs +++ b/Editor/Mono/EditorHandles/BoundsHandle/PrimitiveBoundsHandle.cs @@ -164,12 +164,20 @@ public void DrawHandle() { scaleAxis = 2; } - float scaleFactor = Mathf.Approximately(m_BoundsOnClick.size[scaleAxis], 0f) ? - 1f : size[scaleAxis] / m_BoundsOnClick.size[scaleAxis]; - int nextAxis = s_NextAxis[scaleAxis]; - size[nextAxis] = scaleFactor * m_BoundsOnClick.size[nextAxis]; - nextAxis = s_NextAxis[nextAxis]; - size[nextAxis] = scaleFactor * m_BoundsOnClick.size[nextAxis]; + + if (Mathf.Approximately(m_BoundsOnClick.size[scaleAxis], 0f)) + { + if (m_BoundsOnClick.size == Vector3.zero) + size = Vector3.one * size[scaleAxis]; + } + else + { + var scaleFactor = size[scaleAxis] / m_BoundsOnClick.size[scaleAxis]; + var nextAxis = s_NextAxis[scaleAxis]; + size[nextAxis] = scaleFactor * m_BoundsOnClick.size[nextAxis]; + nextAxis = s_NextAxis[nextAxis]; + size[nextAxis] = scaleFactor * m_BoundsOnClick.size[nextAxis]; + } m_Bounds.size = size; } diff --git a/Editor/Mono/EditorHandles/FreeMove.cs b/Editor/Mono/EditorHandles/FreeMove.cs index c173d409cd..e2258efae0 100644 --- a/Editor/Mono/EditorHandles/FreeMove.cs +++ b/Editor/Mono/EditorHandles/FreeMove.cs @@ -84,16 +84,6 @@ public static Vector3 Do(int id, Vector3 position, Quaternion rotation, float si screenPos += (Vector3)(s_CurrentMousePosition - s_StartMousePosition); position = Handles.inverseMatrix.MultiplyPoint(Camera.current.ScreenToWorldPoint(screenPos)); - // Due to floating point inaccuracies, the back-and-forth transformations used may sometimes introduce - // tiny unintended movement in wrong directions. People notice when using a straight top/left/right ortho camera. - // In that case, just restrain the movement to the plane. - if (Camera.current.transform.forward == Vector3.forward || Camera.current.transform.forward == -Vector3.forward) - position.z = s_StartPosition.z; - if (Camera.current.transform.forward == Vector3.up || Camera.current.transform.forward == -Vector3.up) - position.y = s_StartPosition.y; - if (Camera.current.transform.forward == Vector3.right || Camera.current.transform.forward == -Vector3.right) - position.x = s_StartPosition.x; - if (Tools.vertexDragging) { if (HandleUtility.ignoreRaySnapObjects == null) @@ -224,16 +214,6 @@ public static Vector3 Do(int id, Vector3 position, Quaternion rotation, float si screenPos += (Vector3)(s_CurrentMousePosition - s_StartMousePosition); position = Handles.inverseMatrix.MultiplyPoint(Camera.current.ScreenToWorldPoint(screenPos)); - // Due to floating point inaccuracies, the back-and-forth transformations used may sometimes introduce - // tiny unintended movement in wrong directions. People notice when using a straight top/left/right ortho camera. - // In that case, just restrain the movement to the plane. - if (Camera.current.transform.forward == Vector3.forward || Camera.current.transform.forward == -Vector3.forward) - position.z = s_StartPosition.z; - if (Camera.current.transform.forward == Vector3.up || Camera.current.transform.forward == -Vector3.up) - position.y = s_StartPosition.y; - if (Camera.current.transform.forward == Vector3.right || Camera.current.transform.forward == -Vector3.right) - position.x = s_StartPosition.x; - if (Tools.vertexDragging) { if (HandleUtility.ignoreRaySnapObjects == null) diff --git a/Editor/Mono/EditorHandles/ScaleHandle.cs b/Editor/Mono/EditorHandles/ScaleHandle.cs index 7385194302..63e716a95c 100644 --- a/Editor/Mono/EditorHandles/ScaleHandle.cs +++ b/Editor/Mono/EditorHandles/ScaleHandle.cs @@ -124,6 +124,7 @@ public ScaleHandleParam(Handle handles, Vector3 axisOffset, Vector3 axisSize, Ve } static Vector3 s_DoScaleHandle_AxisHandlesOctant = Vector3.one; + static Vector3 s_InitialScale; public static Vector3 DoScaleHandle(Vector3 scale, Vector3 position, Quaternion rotation, float size) { @@ -155,6 +156,13 @@ internal static Vector3 DoScaleHandle(ScaleHandleIds ids, Vector3 scale, Vector3 var isCenterIsHot = ids.xyz == GUIUtility.hotControl; + switch (Event.current.type) + { + case EventType.MouseDown: + s_InitialScale = scale; + break; + } + for (var i = 0; i < 3; ++i) { if (!param.ShouldShow(i)) @@ -216,12 +224,9 @@ internal static Vector3 DoScaleHandle(ScaleHandleIds ids, Vector3 scale, Vector3 color = ToActiveColorSpace(centerColor); EditorGUI.BeginChangeCheck(); var s = ScaleValueHandle(ids.xyz, scale.x, position, rotation, handleSize * param.xyzSize, CubeHandleCap, SnapSettings.scale); - if (EditorGUI.EndChangeCheck() && !Mathf.Approximately(scale.x, 0)) + if (EditorGUI.EndChangeCheck()) { - var dif = s / scale.x; - scale.x *= dif; - scale.y *= dif; - scale.z *= dif; + scale = s_InitialScale * s; } } diff --git a/Editor/Mono/EditorHandles/VertexSnapping.cs b/Editor/Mono/EditorHandles/VertexSnapping.cs index c6d2638f68..c51b3f74d7 100644 --- a/Editor/Mono/EditorHandles/VertexSnapping.cs +++ b/Editor/Mono/EditorHandles/VertexSnapping.cs @@ -108,6 +108,7 @@ private static void UpdateVertexSnappingOffset() // Important to reset handleOffset before querying handlePosition, // since handlePosition depends on handleOffset. + Tools.InvalidateHandlePosition(); Tools.handleOffset = Vector3.zero; Tools.handleOffset = near - Tools.handlePosition; } diff --git a/Editor/Mono/EditorMode/ModeService.cs b/Editor/Mono/EditorMode/ModeService.cs index 30948226af..9546308e51 100644 --- a/Editor/Mono/EditorMode/ModeService.cs +++ b/Editor/Mono/EditorMode/ModeService.cs @@ -7,9 +7,12 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using JetBrains.Annotations; +using UnityEditor.Experimental.AssetImporters; using UnityEngine; using UnityEngine.Internal; using UnityEngine.UIElements; +using UnityEditor.ShortcutManagement; using JSONObject = System.Collections.IDictionary; @@ -27,6 +30,25 @@ internal enum ModeCapability Playbar } + [Serializable] + class ModeDescriptor : ScriptableObject + { + [SerializeField] public string path; + } + + [UsedImplicitly, ExcludeFromPreset, ScriptedImporter(version: 1, ext: "mode")] + class ModeDescriptorImporter : ScriptedImporter + { + public override void OnImportAsset(AssetImportContext ctx) + { + var modeDescriptor = ScriptableObject.CreateInstance(); + modeDescriptor.path = ctx.assetPath; + modeDescriptor.hideFlags = HideFlags.NotEditable; + ctx.AddObjectToAsset("mode", modeDescriptor); + ctx.SetMainObject(modeDescriptor); + } + } + [ExcludeFromDocs] public static class ModeService { @@ -64,18 +86,10 @@ public struct ModeChangedArgs static ModeService() { - LoadModes(); + LoadModes(true); modeChanged += OnModeChangeMenus; modeChanged += OnModeChangeLayouts; - EditorApplication.projectWasLoaded += LoadModes; - } - - private static void LoadModes() - { - ScanModes(); - SetModeIndex(LoadProjectPrefModeIndex()); - EditorApplication.delayCall += () => RaiseModeChanged(-1, currentIndex); } public static void ChangeModeById(string modeId) @@ -205,7 +219,13 @@ internal static void Refresh(CommandExecuteContext c) internal static void RaiseModeChanged(int prevIndex, int nextIndex) { modeChanged?.Invoke(new ModeChangedArgs { prevIndex = prevIndex, nextIndex = nextIndex }); - EditorUtility.Internal_UpdateAllMenus(); + + // Not required when you start the editor in the default mode. + if (prevIndex != -1 || nextIndex != 0) + { + EditorUtility.Internal_UpdateAllMenus(); + ShortcutIntegration.instance.RebuildShortcuts(); + } } internal static bool IsValidModeId(string id) @@ -213,27 +233,88 @@ internal static bool IsValidModeId(string id) return !string.IsNullOrEmpty(id) && id.All(c => char.IsLetterOrDigit(c) || c == '_' || c == '-' || c == '.'); } + internal static string GetDefaultModeLayout(string modeId = null) + { + var layouts = GetModeDataSection(currentIndex, k_LayoutsSectionName) as IList; + if (layouts != null && layouts.Count > 0) + { + var layoutPath = layouts[0] as string; + if (layoutPath != null) + { + if (File.Exists(layoutPath)) + { + return layoutPath; + } + else + { + Debug.LogWarning("Default Mode Layout: " + layoutPath + " doesn't exists."); + } + } + } + return null; + } + + internal static bool HasStartupMode() + { + return Application.HasARGV("editor-mode"); + } + + private static void LoadModes(bool checkStartupMode = false) + { + ScanModes(); + var currentModeIndex = LoadProjectPrefModeIndex(); + if (checkStartupMode && HasStartupMode()) + { + var requestEditorMode = Application.GetValueForARGV("editor-mode"); + var modeIndex = Array.FindIndex(modes, m => m.id == requestEditorMode); + if (modeIndex != -1) + { + currentModeIndex = modeIndex; + SaveProjectPrefModeIndex(currentModeIndex); + } + } + + SetModeIndex(currentModeIndex); + EditorApplication.delayCall += () => RaiseModeChanged(-1, currentIndex); + } + private static void ScanModes() { var modesData = new Dictionary { [k_DefaultModeId] = new Dictionary { [k_LabelSectionName] = "Default" } }; - var modeFilePaths = AssetDatabase.GetAllAssetPaths().Where(IsEditorModeDescriptor).OrderBy(path => - new FileInfo(path).Length); - foreach (var modeFilePath in modeFilePaths) + var modeDescriptors = AssetDatabase.EnumerateAllAssets(new SearchFilter { - var json = SJSON.Load(modeFilePath); - - foreach (var rawModeId in json.Keys) + searchArea = SearchFilter.SearchArea.InPackagesOnly, + classNames = new[] { nameof(ModeDescriptor) }, + skipHidden = true, + showAllHits = true + }); + while (modeDescriptors.MoveNext()) + { + var md = modeDescriptors.Current.pptrValue as ModeDescriptor; + if (md == null) + continue; + try { - var modeId = ((string)rawModeId).ToLower(); - if (!IsValidModeId(modeId)) + var json = SJSON.Load(md.path); + foreach (var rawModeId in json.Keys) { - Debug.Log($"Invalid Mode Id: {modeId} contains non alphanumeric characters."); - continue; + var modeId = ((string)rawModeId).ToLower(); + if (IsValidModeId(modeId)) + { + if (modesData.ContainsKey(modeId)) + modesData[modeId] = JsonUtils.DeepMerge(modesData[modeId] as JSONObject, json[modeId] as JSONObject); + else + modesData[modeId] = json[modeId]; + } + else + { + Debug.LogWarning($"Invalid Mode Id: {modeId} contains non alphanumeric characters."); + } } - - if (modesData.ContainsKey(modeId)) - modesData[modeId] = JsonUtils.DeepMerge(modesData[modeId] as JSONObject, json[modeId] as JSONObject); - else - modesData[modeId] = json[modeId]; + } + catch (Exception ex) + { + Debug.LogError($"[ModeService] Error while parsing mode file {md.path}.\n{ex}"); } } @@ -334,6 +415,7 @@ private static void LoadMenu(IList menus, string prefix = "", int priority = 100 var menuName = JsonUtils.JsonReadString(menu, k_MenuKeyName); var fullMenuName = prefix + menuName; var platform = JsonUtils.JsonReadString(menu, k_MenuKeyPlatform); + var hasExplicitPriority = menu.Contains(k_MenuKeyPriority); priority = JsonUtils.JsonReadInt(menu, k_MenuKeyPriority, priority + 1); // Check the menu item platform @@ -350,7 +432,7 @@ private static void LoadMenu(IList menus, string prefix = "", int priority = 100 var whitelistedItems = Menu.ExtractSubmenus(fullMenuName); var renamedTo = prefix + JsonUtils.JsonReadString(menu, k_MenuKeyRename, menuName); foreach (var wi in whitelistedItems) - Menu.AddExistingMenuItem(wi.Replace(fullMenuName, renamedTo), wi, priority); + Menu.AddExistingMenuItem(wi.Replace(fullMenuName, renamedTo), wi, hasExplicitPriority ? priority : -1); } } else @@ -404,28 +486,20 @@ private static void OnModeChangeLayouts(ModeChangedArgs args) if (args.prevIndex == -1) return; - if (HasCapability(ModeCapability.LayoutSwitching, true)) - { - // Save previous mode layout - var prevLayoutPath = Path.Combine(Application.temporaryCachePath, $"{k_ModeLayoutKeyName}-{GetModeId(args.prevIndex)}.wlt"); - WindowLayout.SaveWindowLayout(prevLayoutPath); + if (!HasCapability(ModeCapability.LayoutSwitching, true)) + return; - // Load exiting layout if available - var modeLayoutPath = Path.Combine(Application.temporaryCachePath, $"{k_ModeLayoutKeyName}-{GetModeId(args.nextIndex)}.wlt"); - if (File.Exists(modeLayoutPath)) - { - WindowLayout.LoadWindowLayout(modeLayoutPath, false, false, true); - } - else - { - var layouts = GetModeDataSection(args.nextIndex, k_LayoutsSectionName) as IList; - if (layouts != null && layouts.Count > 0) - { - var layoutPath = layouts[0] as string; - if (layoutPath != null) - WindowLayout.LoadWindowLayout(layoutPath, false, false, true); - } - } + WindowLayout.SaveCurrentLayoutPerMode(GetModeId(args.prevIndex)); + + try + { + // Load the last valid layout for this mode + WindowLayout.LoadDefaultWindowPreferencesEx(true); + } + catch (Exception) + { + // Error while loading layout. Load the default layout for current mode. + WindowLayout.LoadDefaultLayout(); } WindowLayout.ReloadWindowLayoutMenu(); diff --git a/Editor/Mono/EditorResources.cs b/Editor/Mono/EditorResources.cs index c06dc22de6..c4b14caa25 100644 --- a/Editor/Mono/EditorResources.cs +++ b/Editor/Mono/EditorResources.cs @@ -21,7 +21,6 @@ public partial class EditorResources static EditorResources() { styleCatalog = new StyleCatalog(); - styleCatalog.Load(GetDefaultStyleCatalogPaths()); } private static bool CanEnableExtendedStyles() @@ -57,7 +56,7 @@ internal static void BuildCatalog() { styleCatalog = new StyleCatalog(); var paths = GetDefaultStyleCatalogPaths(); - foreach (var editorUssPath in AssetDatabase.GetAllAssetPaths().Where(IsEditorStyleSheet)) + foreach (var editorUssPath in AssetDatabase.FindAssets("t:StyleSheet").Select(AssetDatabase.GUIDToAssetPath).Where(IsEditorStyleSheet)) paths.Add(editorUssPath); styleCatalog.Load(paths); @@ -67,7 +66,9 @@ internal static void BuildCatalog() var skin = GUIUtility.GetDefaultSkin(); if (skin != null) { - ConverterUtils.ResetSkinToPristine(skin, EditorGUIUtility.isProSkin ? SkinTarget.Dark : SkinTarget.Light); + // TODO: Emit OnStyleCatalogLoaded + if (Path.GetFileName(Path.GetDirectoryName(Application.dataPath)) == "editor_resources") + ConverterUtils.ResetSkinToPristine(skin, EditorGUIUtility.isProSkin ? SkinTarget.Dark : SkinTarget.Light); UpdateGUIStyleProperties(skin); } } diff --git a/Editor/Mono/EditorUserBuildSettings.bindings.cs b/Editor/Mono/EditorUserBuildSettings.bindings.cs index 49782a71f9..8ac98c92aa 100644 --- a/Editor/Mono/EditorUserBuildSettings.bindings.cs +++ b/Editor/Mono/EditorUserBuildSettings.bindings.cs @@ -423,6 +423,8 @@ public static extern AndroidETC2Fallback androidETC2Fallback [Obsolete("androidUseLegacySdkTools has been deprecated. It does not have any effect.")] public static extern bool androidUseLegacySdkTools { get; set; } + public static extern bool androidCreateSymbolsZip { get; set; } + // *undocumented* // NOTE: This setting should probably not be a part of the public API as is. Atm it is used by playmode tests // and applied during build post-processing. We will however move towards separating building and launching diff --git a/Editor/Mono/EditorUserSettings.bindings.cs b/Editor/Mono/EditorUserSettings.bindings.cs index 49d908b6e4..cc94a79eb7 100644 --- a/Editor/Mono/EditorUserSettings.bindings.cs +++ b/Editor/Mono/EditorUserSettings.bindings.cs @@ -46,6 +46,9 @@ public static string GetConfigValue(string name) [NativeProperty("VCShowFailedCheckout")] public static extern bool showFailedCheckout { get; set; } + [NativeProperty("VCOverwriteFailedCheckoutAssets")] + public static extern bool overwriteFailedCheckoutAssets { get; set; } + [NativeProperty("VCAllowAsyncUpdate")] public static extern bool allowAsyncStatusUpdate { get; set; } diff --git a/Editor/Mono/EditorUtility.bindings.cs b/Editor/Mono/EditorUtility.bindings.cs index d204d99db2..900393e4b2 100644 --- a/Editor/Mono/EditorUtility.bindings.cs +++ b/Editor/Mono/EditorUtility.bindings.cs @@ -53,11 +53,13 @@ public static bool DisplayDialog(string title, string message, string ok) public static extern bool IsPersistent(Object target); public static extern string SaveFilePanel(string title, string directory, string defaultName, string extension); public static extern int NaturalCompare(string a, string b); - public static extern void SetDirty([NotNull] Object target); public static extern Object InstanceIDToObject(int instanceID); public static extern void CompressTexture([NotNull] Texture2D texture, TextureFormat format, int quality); public static extern void CompressCubemapTexture([NotNull] Cubemap texture, TextureFormat format, int quality); + [FreeFunction("EditorUtility::SetDirtyObjectOrScene")] + public static extern void SetDirty([NotNull] Object target); + [FreeFunction("InvokeDiffTool")] public static extern string InvokeDiffTool(string leftTitle, string leftFile, string rightTitle, string rightFile, string ancestorTitle, string ancestorFile); diff --git a/Editor/Mono/EditorUtility.cs b/Editor/Mono/EditorUtility.cs index 5500518084..373b091d44 100644 --- a/Editor/Mono/EditorUtility.cs +++ b/Editor/Mono/EditorUtility.cs @@ -347,7 +347,7 @@ internal static void DisplayObjectContextMenu(Rect position, Object[] context, i info.instanceObject = targetComponent; info.assetPath = AssetDatabase.GetAssetPath(sourceGo); GameObject rootObject = PrefabUtility.GetRootGameObject(sourceGo); - if (!PrefabUtility.IsPartOfPrefabThatCanBeAppliedTo(rootObject)) + if (!PrefabUtility.IsPartOfPrefabThatCanBeAppliedTo(rootObject) || EditorUtility.IsPersistent(instanceGo)) pm.AddDisabledItem(menuItemContent); else pm.AddItem(menuItemContent, false, TargetChoiceHandler.ApplyPrefabAddedComponent, info); @@ -387,7 +387,7 @@ internal static void DisplayObjectContextMenu(Rect position, Object[] context, i info.instanceObject = targetObject; info.assetPath = AssetDatabase.GetAssetPath(sourceObject); GameObject rootObject = PrefabUtility.GetRootGameObject(sourceObject); - if (!PrefabUtility.IsPartOfPrefabThatCanBeAppliedTo(rootObject)) + if (!PrefabUtility.IsPartOfPrefabThatCanBeAppliedTo(rootObject) || EditorUtility.IsPersistent(targetObject)) pm.AddDisabledItem(menuItemContent); else pm.AddItem(menuItemContent, false, TargetChoiceHandler.ApplyPrefabObjectOverride, info); diff --git a/Editor/Mono/EditorWindow.cs b/Editor/Mono/EditorWindow.cs index 9080e593df..27d4491ff9 100644 --- a/Editor/Mono/EditorWindow.cs +++ b/Editor/Mono/EditorWindow.cs @@ -757,7 +757,17 @@ public static T GetWindow(string title, bool focus, params System.Type[] desi return win; } - win = CreateInstance(); + return CreateWindow(title, desiredDockNextTo); + } + + public static T CreateWindow(params System.Type[] desiredDockNextTo) where T : EditorWindow + { + return CreateWindow(null, desiredDockNextTo); + } + + public static T CreateWindow(string title, params System.Type[] desiredDockNextTo) where T : EditorWindow + { + T win = CreateInstance(); if (title != null) win.titleContent = new GUIContent(title); diff --git a/Editor/Mono/GUI/AboutWindow.cs b/Editor/Mono/GUI/AboutWindow.cs index 4ae1d5e2d0..f24790a713 100644 --- a/Editor/Mono/GUI/AboutWindow.cs +++ b/Editor/Mono/GUI/AboutWindow.cs @@ -142,7 +142,7 @@ public void OnGUI() GUILayout.Label(s_MonoLogo); GUILayout.Label("Scripting powered by The Mono Project.\n\n(c) 2011 Novell, Inc.", "MiniLabel", GUILayout.Width(200)); GUILayout.Label(s_AgeiaLogo); - GUILayout.Label("Physics powered by PhysX.\n\n(c) 2011 NVIDIA Corporation.", "MiniLabel", GUILayout.Width(200)); + GUILayout.Label("Physics powered by PhysX.\n\n(c) 2018 NVIDIA Corporation.", "MiniLabel", GUILayout.Width(200)); GUILayout.EndHorizontal(); GUILayout.FlexibleSpace(); GUILayout.BeginHorizontal(); diff --git a/Editor/Mono/GUI/DockArea.cs b/Editor/Mono/GUI/DockArea.cs index 36c5a7ecd7..bec55024ef 100644 --- a/Editor/Mono/GUI/DockArea.cs +++ b/Editor/Mono/GUI/DockArea.cs @@ -136,6 +136,7 @@ protected override void OnDestroy() // Avoid destroying a window that has already being destroyed (case 967778) if (w == null) continue; + UnityEngine.Object.DestroyImmediate(w, true); } @@ -672,12 +673,15 @@ protected override void AddDefaultItemsToMenu(GenericMenu menu, EditorWindow vie menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Close Tab")); menu.AddSeparator(""); - System.Type[] types = GetPaneTypes(); + IEnumerable types = GetPaneTypes(); GUIContent baseContent = EditorGUIUtility.TrTextContent("Add Tab"); - foreach (System.Type t in types) + foreach (Type t in types) { if (t == null) + { + menu.AddSeparator(baseContent.text + "/"); continue; + } GUIContent entry = new GUIContent(EditorWindow.GetLocalizedTitleContentFromType(t)); // make a copy since we modify the text below entry.text = baseContent.text + "/" + entry.text; @@ -685,7 +689,7 @@ protected override void AddDefaultItemsToMenu(GenericMenu menu, EditorWindow vie } menu.AddSeparator(""); - menu.AddItem(EditorGUIUtility.TextContent("UIElements Debugger _%f5"), false, DebugWindow, view); + AddUIElementsDebuggerToMenu(menu); } void AddTabToHere(object userData) @@ -1113,13 +1117,16 @@ protected override void AddDefaultItemsToMenu(GenericMenu menu, EditorWindow win menu.AddItem(EditorGUIUtility.TrTextContent("Maximize"), !(parent is SplitView), Unmaximize, window); menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Close Tab")); menu.AddSeparator(""); - System.Type[] types = GetPaneTypes(); + IEnumerable types = GetPaneTypes(); GUIContent baseContent = EditorGUIUtility.TrTextContent("Add Tab"); - foreach (System.Type t in types) + foreach (Type t in types) { if (t == null) + { + menu.AddSeparator(baseContent.text + "/"); continue; + } GUIContent entry = new GUIContent(EditorWindow.GetLocalizedTitleContentFromType(t)); // make a copy since we modify the text below entry.text = baseContent.text + "/" + entry.text; @@ -1127,7 +1134,7 @@ protected override void AddDefaultItemsToMenu(GenericMenu menu, EditorWindow win } menu.AddSeparator(""); - menu.AddItem(EditorGUIUtility.TextContent("UIElements Debugger _%f5"), false, DebugWindow, window); + AddUIElementsDebuggerToMenu(menu); } } } diff --git a/Editor/Mono/GUI/EditorStyles.cs b/Editor/Mono/GUI/EditorStyles.cs index f5d19e0b66..08bec332a4 100644 --- a/Editor/Mono/GUI/EditorStyles.cs +++ b/Editor/Mono/GUI/EditorStyles.cs @@ -46,7 +46,7 @@ public sealed class EditorStyles private GUIStyle m_WordWrappedLabel; // Style for link label. - internal static GUIStyle linkLabel { get { return s_Current.m_LinkLabel; } } + public static GUIStyle linkLabel { get { return s_Current.m_LinkLabel; } } private GUIStyle m_LinkLabel; // Style for white label. diff --git a/Editor/Mono/GUI/MaskFieldGUI.cs b/Editor/Mono/GUI/MaskFieldGUI.cs index 1a667890de..2d5ea383eb 100644 --- a/Editor/Mono/GUI/MaskFieldGUI.cs +++ b/Editor/Mono/GUI/MaskFieldGUI.cs @@ -172,7 +172,7 @@ internal static void GetMenuOptions(int mask, string[] flagNames, int[] flagValu var flagEndIndex = flagStartIndex + flagCount; // Button text - buttonText = "Mixed ..."; + buttonText = "Mixed..."; if (mask == 0) buttonText = nothingName; else if (mask == ~0) diff --git a/Editor/Mono/GUI/PopupWindow.cs b/Editor/Mono/GUI/PopupWindow.cs index 8ab95b6ae0..a893de091c 100644 --- a/Editor/Mono/GUI/PopupWindow.cs +++ b/Editor/Mono/GUI/PopupWindow.cs @@ -136,7 +136,6 @@ internal void CloseContent() { if (m_WindowContent != null) m_WindowContent.OnClose(); - m_WindowContent = null; } } } diff --git a/Editor/Mono/GUI/PreviewResizer.cs b/Editor/Mono/GUI/PreviewResizer.cs index bddc0d3285..fe6d922fd0 100644 --- a/Editor/Mono/GUI/PreviewResizer.cs +++ b/Editor/Mono/GUI/PreviewResizer.cs @@ -39,6 +39,8 @@ private int id } } + public bool localFrame { get; set; } + // Instances of this class should be serialized. // The Init function will only have effect if the serialized values are not already set. public void Init(string prefName) @@ -84,7 +86,7 @@ public float ResizeHandle(Rect windowPosition, float minSize, float minRemaining } bool expandedBefore = expanded; - previewSize = -PixelPreciseCollapsibleSlider(id, resizerRect, -previewSize, -maxPreviewSize, -0, ref expanded); + previewSize = -PixelPreciseCollapsibleSlider(id, resizerRect, -previewSize, -maxPreviewSize, -0, ref expanded, localFrame); previewSize = Mathf.Min(previewSize, maxPreviewSize); dragging = (GUIUtility.hotControl == id); @@ -173,7 +175,13 @@ public void ToggleExpanded() } // This is the slider behavior for resizing the preview area - public static float PixelPreciseCollapsibleSlider(int id, Rect position, float value, float min, float max, ref bool expanded) + public static float PixelPreciseCollapsibleSlider(int id, Rect position, float value, float min, float max, + ref bool expanded) + { + return PixelPreciseCollapsibleSlider(id, position, value, min, max, ref expanded, false); + } + + public static float PixelPreciseCollapsibleSlider(int id, Rect position, float value, float min, float max, ref bool expanded, bool localFrame) { Event evt = Event.current; @@ -182,8 +190,13 @@ public static float PixelPreciseCollapsibleSlider(int id, Rect position, float v return value; } - var mousePosition = GUIClip.UnclipToWindow(evt.mousePosition); - mousePosition.y -= Editor.k_HeaderHeight; + var mousePosition = evt.mousePosition; + + if (localFrame) + { + mousePosition = GUIClip.UnclipToWindow(evt.mousePosition); + mousePosition.y -= Editor.k_HeaderHeight; + } switch (evt.GetTypeForControl(id)) { @@ -216,8 +229,14 @@ public static float PixelPreciseCollapsibleSlider(int id, Rect position, float v } break; case EventType.Repaint: - const float x = 0f; - const float y = 0f; + float x = position.x; + float y = position.y; + + if (localFrame) + { + x = 0f; + y = 0f; + } if (GUIUtility.hotControl == 0) { diff --git a/Editor/Mono/GUI/ReorderableList.cs b/Editor/Mono/GUI/ReorderableList.cs index 66b15b6112..0a46143334 100644 --- a/Editor/Mono/GUI/ReorderableList.cs +++ b/Editor/Mono/GUI/ReorderableList.cs @@ -31,6 +31,7 @@ public class ReorderableList public delegate void ChangedCallbackDelegate(ReorderableList list); public delegate bool CanRemoveCallbackDelegate(ReorderableList list); public delegate bool CanAddCallbackDelegate(ReorderableList list); + public delegate void DragCallbackDelegate(ReorderableList list); // draw callbacks @@ -51,6 +52,7 @@ public class ReorderableList public AddCallbackDelegate onAddCallback; public AddDropdownCallbackDelegate onAddDropdownCallback; public RemoveCallbackDelegate onRemoveCallback; + public DragCallbackDelegate onMouseDragCallback; public SelectCallbackDelegate onMouseUpCallback; public CanRemoveCallbackDelegate onCanRemoveCallback; public CanAddCallbackDelegate onCanAddCallback; @@ -707,6 +709,9 @@ private void DoDraggingAndSelection(Rect listRect) // Set m_Dragging state on first MouseDrag event after we got hotcontrol (to prevent animating elements when deleting elements by context menu) m_Dragging = true; + if (onMouseDragCallback != null) + onMouseDragCallback(this); + // if we are dragging, update the position UpdateDraggedY(listRect); evt.Use(); diff --git a/Editor/Mono/GUI/Toolbar.cs b/Editor/Mono/GUI/Toolbar.cs index a31bf74431..3e5ea5c502 100644 --- a/Editor/Mono/GUI/Toolbar.cs +++ b/Editor/Mono/GUI/Toolbar.cs @@ -153,6 +153,8 @@ internal static string lastLoadedLayoutName } set { + if (!get) + return; get.m_LastLoadedLayoutName = value; get.Repaint(); } diff --git a/Editor/Mono/GUI/Tools/BuiltinTools.cs b/Editor/Mono/GUI/Tools/BuiltinTools.cs index 222730caaf..509e9c2ac7 100644 --- a/Editor/Mono/GUI/Tools/BuiltinTools.cs +++ b/Editor/Mono/GUI/Tools/BuiltinTools.cs @@ -406,7 +406,7 @@ protected override void ToolGUI(SceneView view, Vector3 handlePosition, bool isS GUI.color = fadedColor; } - Vector3 oldPivot = Tools.GetHandlePosition(); + Vector3 oldPivot = Tools.cachedHandlePosition; // Pivot handle if (!Tools.vertexDragging) diff --git a/Editor/Mono/GUI/Tools/EditorToolContext.cs b/Editor/Mono/GUI/Tools/EditorToolContext.cs index 1f5f9c4f62..1103da012d 100644 --- a/Editor/Mono/GUI/Tools/EditorToolContext.cs +++ b/Editor/Mono/GUI/Tools/EditorToolContext.cs @@ -85,6 +85,8 @@ internal static EditorTool activeTool Tools.SyncToolEnum(); + Tools.InvalidateHandlePosition(); + s_ChangingActiveTool = false; } } diff --git a/Editor/Mono/GUI/Tools/Tools.cs b/Editor/Mono/GUI/Tools/Tools.cs index 9029631cef..2667ddaf56 100644 --- a/Editor/Mono/GUI/Tools/Tools.cs +++ b/Editor/Mono/GUI/Tools/Tools.cs @@ -134,6 +134,27 @@ internal static bool viewToolActive } } + static Vector3 s_HandlePosition; + static bool s_HandlePositionComputed; + + internal static Vector3 cachedHandlePosition + { + get + { + if (!s_HandlePositionComputed) + { + s_HandlePosition = GetHandlePosition(); + s_HandlePositionComputed = true; + } + return s_HandlePosition; + } + } + + internal static void InvalidateHandlePosition() + { + s_HandlePositionComputed = false; + } + public static Vector3 handlePosition { get @@ -145,7 +166,7 @@ public static Vector3 handlePosition if (s_LockHandlePositionActive) return s_LockHandlePosition; - return GetHandlePosition(); + return cachedHandlePosition; } } @@ -278,6 +299,7 @@ public static PivotMode pivotMode { get.m_PivotMode = value; EditorPrefs.SetInt("PivotMode", (int)pivotMode); + InvalidateHandlePosition(); } } } @@ -405,6 +427,7 @@ private void OnEnable() internal static void OnSelectionChange() { ResetGlobalHandleRotation(); + InvalidateHandlePosition(); localHandleOffset = Vector3.zero; } diff --git a/Editor/Mono/GUI/TreeView/AssetOrGameObjectTreeViewDragging.cs b/Editor/Mono/GUI/TreeView/AssetOrGameObjectTreeViewDragging.cs index af16cfc8f1..0d868af249 100644 --- a/Editor/Mono/GUI/TreeView/AssetOrGameObjectTreeViewDragging.cs +++ b/Editor/Mono/GUI/TreeView/AssetOrGameObjectTreeViewDragging.cs @@ -30,10 +30,13 @@ public override bool CanStartDrag(TreeViewItem targetItem, List draggedItem foreach (var draggedItemID in draggedItemIDs) { var path = AssetDatabase.GetAssetPath(draggedItemID); - bool rootFolder, readOnly; - var validPath = AssetDatabase.GetAssetFolderInfo(path, out rootFolder, out readOnly); - if (!validPath || rootFolder || readOnly) - return false; + if (AssetDatabase.IsValidFolder(path)) + { + bool rootFolder, readOnly; + var validPath = AssetDatabase.GetAssetFolderInfo(path, out rootFolder, out readOnly); + if (!validPath || rootFolder || readOnly) + return false; + } } return true; } diff --git a/Editor/Mono/GUI/TreeView/GameObjectTreeViewGUI.cs b/Editor/Mono/GUI/TreeView/GameObjectTreeViewGUI.cs index 91f961e19a..d7a1d5ecf7 100644 --- a/Editor/Mono/GUI/TreeView/GameObjectTreeViewGUI.cs +++ b/Editor/Mono/GUI/TreeView/GameObjectTreeViewGUI.cs @@ -10,6 +10,7 @@ using UnityEditor.IMGUI.Controls; using UnityEditor.SceneManagement; using UnityEngine; +using UnityEngine.Assertions.Comparers; using UnityEngine.SceneManagement; using Object = UnityEngine.Object; @@ -76,6 +77,7 @@ public override void OnInitialize() dataSource.beforeReloading += SubSceneGUI.FetchSubSceneInfo; m_PrevScollPos = m_TreeView.state.scrollPos.y; m_PrevTotalHeight = m_TreeView.GetTotalRect().height; + k_BaseIndent = SceneVisibilityHierarchyGUI.utilityBarWidth; } private void SceneVisibilityManagerOnVisibilityChanged() @@ -333,11 +335,8 @@ override protected void DoItemGUI(Rect rect, int row, TreeViewItem item, bool se useBoldFont = (goItem.scene == SceneManager.GetActiveScene()) || IsPrefabStageHeader(goItem); } - SceneVisibilityHierarchyGUI.DoItemGUI(rect, goItem, selected && !IsRenaming(item.id), m_TreeView.hoveredItem == goItem, focused, isDragging); - - rect.xMin += SceneVisibilityHierarchyGUI.utilityBarWidth; - base.DoItemGUI(rect, row, item, selected, focused, useBoldFont); + SceneVisibilityHierarchyGUI.DoItemGUI(rect, goItem, selected && !IsRenaming(item.id), m_TreeView.hoveredItem == goItem, focused, isDragging); if (goItem.isSceneHeader) { @@ -356,7 +355,7 @@ override protected void DoItemGUI(Rect rect, int row, TreeViewItem item, bool se protected override Rect GetDropTargetRect(Rect rect) { - rect.xMin -= SceneVisibilityHierarchyGUI.utilityBarWidth; + rect.xMin += SceneVisibilityHierarchyGUI.utilityBarWidth; return rect; } @@ -367,7 +366,9 @@ protected void DoAdditionalSceneHeaderGUI(GameObjectTreeViewItem goItem, Rect re const float optionsButtonWidth = 16f; const float optionsButtonHeight = 6f; const float margin = 4f; + Rect buttonRect = new Rect(rect.width - optionsButtonWidth - margin, rect.y + (rect.height - optionsButtonHeight) * 0.5f, optionsButtonWidth, rect.height); + if (Event.current.type == EventType.Repaint) GameObjectStyles.optionsButtonStyle.Draw(buttonRect, false, false, false, false); diff --git a/Editor/Mono/GUI/TreeView/TreeViewControl/TreeViewControl.cs b/Editor/Mono/GUI/TreeView/TreeViewControl/TreeViewControl.cs index 94199e0b84..6de2bd5e14 100644 --- a/Editor/Mono/GUI/TreeView/TreeViewControl/TreeViewControl.cs +++ b/Editor/Mono/GUI/TreeView/TreeViewControl/TreeViewControl.cs @@ -29,6 +29,15 @@ protected GetNewSelectionFunction getNewSelectionOverride set { m_TreeView.getNewSelectionOverride = (x, y, z) => value(x, y, z); } } + internal bool deselectOnUnhandledMouseDown + { + set + { + if (m_TreeView != null) + m_TreeView.deselectOnUnhandledMouseDown = value; + } + } + TreeViewController m_TreeView; TreeViewControlDataSource m_DataSource; TreeViewControlGUI m_GUI; diff --git a/Editor/Mono/GUI/TreeView/TreeViewGUI.cs b/Editor/Mono/GUI/TreeView/TreeViewGUI.cs index 691d75758a..146638fbe3 100644 --- a/Editor/Mono/GUI/TreeView/TreeViewGUI.cs +++ b/Editor/Mono/GUI/TreeView/TreeViewGUI.cs @@ -257,8 +257,7 @@ virtual protected void DoItemGUI(Rect rect, int row, TreeViewItem item, bool sel // Draw drop marker if (isDropTarget) { - GetDropTargetRect(rect); - Styles.lineStyle.Draw(rect, GUIContent.none, true, true, false, false); + Styles.lineStyle.Draw(GetDropTargetRect(rect), GUIContent.none, true, true, false, false); } // Show insertion marker below this item (rendered end of rows) @@ -398,6 +397,7 @@ virtual public void BeginPingItem(TreeViewItem item, float topPixelOfRow, float topPixelOfRow, k_IconWidth + k_SpaceBetweenIconAndText + contentSize.x + iconTotalPadding, contentSize.y); + m_Ping.m_AvailableWidth = availableWidth; int row = m_TreeView.data.GetRow(item.id); diff --git a/Editor/Mono/GUI/TypeSelectionList.cs b/Editor/Mono/GUI/TypeSelectionList.cs index a5c560bac4..d02cec9b74 100644 --- a/Editor/Mono/GUI/TypeSelectionList.cs +++ b/Editor/Mono/GUI/TypeSelectionList.cs @@ -23,6 +23,9 @@ public TypeSelectionList(Object[] objects) foreach (Object o in objects) { string typeName = ObjectNames.GetTypeName(o); + if (o is GameObject && EditorUtility.IsPersistent(o)) + typeName = "Prefab"; + if (!types.ContainsKey(typeName)) types[typeName] = new List(); types[typeName].Add(o); @@ -48,7 +51,10 @@ public TypeSelection(string typeName, Object[] objects) System.Diagnostics.Debug.Assert(objects != null && objects.Length >= 1); this.objects = objects; label = new GUIContent(objects.Length + " " + ObjectNames.NicifyVariableName(typeName) + (objects.Length > 1 ? "s" : "")); - label.image = AssetPreview.GetMiniTypeThumbnail(objects[0]); + if (objects[0] is GameObject) + label.image = EditorUtility.IsPersistent(objects[0]) ? PrefabUtility.GameObjectStyles.prefabIcon : PrefabUtility.GameObjectStyles.gameObjectIcon; + else + label.image = AssetPreview.GetMiniTypeThumbnail(objects[0]); } public int CompareTo(object o) diff --git a/Editor/Mono/GUI/WindowLayout.cs b/Editor/Mono/GUI/WindowLayout.cs index dec06c46eb..80e189fc96 100644 --- a/Editor/Mono/GUI/WindowLayout.cs +++ b/Editor/Mono/GUI/WindowLayout.cs @@ -26,40 +26,38 @@ internal static class WindowLayout { private const string kMaximizeRestoreFile = "CurrentMaximizeLayout.dwlt"; private const string kLastLayoutName = "LastLayout.dwlt"; - private const string kCurrentLayoutPath = "Library/CurrentLayout.dwlt"; private const string kDefaultLayoutName = "Default.wlt"; + // Backward compatibility: name of the old (non mode specific) per project layout + internal const string kOldCurrentLayoutPath = "Library/CurrentLayout.dwlt"; + internal static string layoutsPreferencesPath => FileUtil.CombinePaths(InternalEditorUtility.unityPreferencesFolder, "Layouts"); + internal static string layoutsModePreferencesPath => FileUtil.CombinePaths(layoutsPreferencesPath, ModeService.currentId); + internal static string layoutsDefaultModePreferencesPath => FileUtil.CombinePaths(layoutsPreferencesPath, "default"); + internal static string layoutsProjectPath => Directory.GetCurrentDirectory() + "/Library"; + // Backward compatibility: property for old global layout (for default mode only) + internal static string OldGlobalLayoutPath => Path.Combine(layoutsPreferencesPath, "__Current__.dwlt"); + internal static string ProjectLayoutPath => GetProjectLayoutPerMode(ModeService.currentId); + internal static string LastLayoutPath => Path.Combine(layoutsModePreferencesPath, kLastLayoutName); [UsedImplicitly, RequiredByNativeCode] public static void LoadDefaultWindowPreferences() { - InitializeLayoutPreferencesFolder(); + LoadDefaultWindowPreferencesEx(false); + } - // Upgrade path from global layout state to per-project layout state - string lastLayoutPath = Path.Combine(layoutsPreferencesPath, kLastLayoutName); - string oldCurrentLayoutPath = Path.Combine(layoutsPreferencesPath, "__Current__.dwlt"); - if (File.Exists(oldCurrentLayoutPath) && !File.Exists(lastLayoutPath)) + public static void LoadDefaultWindowPreferencesEx(bool keepMainWindow) + { + InitializeLayoutPreferencesFolder(); + var projectLayoutExists = File.Exists(ProjectLayoutPath); + if (!projectLayoutExists) { - // For projects that were using the global layout state, we'll use the last layout state used. - // In the case of Unity's first run, the last layout state will be the old global layout state. - FileUtil.CopyFileOrDirectory(oldCurrentLayoutPath, lastLayoutPath); + var currentLayoutPath = GetCurrentLayoutPath(); + FileUtil.CopyFileOrDirectory(currentLayoutPath, ProjectLayoutPath); } - bool newProjectLayout = !File.Exists(kCurrentLayoutPath); - - // Make sure we have a current layout file created - if (newProjectLayout) - { - if (File.Exists(lastLayoutPath)) - // First we try to load the last layout - FileUtil.CopyFileOrDirectory(lastLayoutPath, kCurrentLayoutPath); - else - // Otherwise we load the default layout that the user could've modified - FileUtil.CopyFileOrDirectory(GetDefaultLayoutPath(), kCurrentLayoutPath); - } - Debug.Assert(File.Exists(kCurrentLayoutPath)); + Debug.Assert(File.Exists(ProjectLayoutPath)); // Load the current project layout - LoadWindowLayout(kCurrentLayoutPath, newProjectLayout); + LoadWindowLayout(ProjectLayoutPath, !projectLayoutExists, false, keepMainWindow); } [UsedImplicitly, RequiredByNativeCode] @@ -69,20 +67,61 @@ public static void SaveDefaultWindowPreferences() if (!InternalEditorUtility.isHumanControllingUs) return; - // Save Project Current Layout - SaveWindowLayout(Path.Combine(Directory.GetCurrentDirectory(), kCurrentLayoutPath)); + SaveCurrentLayoutPerMode(ModeService.currentId); + } - // Make sure we have a layout directory to save the last layout. - if (!Directory.Exists(layoutsPreferencesPath)) - Directory.CreateDirectory(layoutsPreferencesPath); + internal static void SaveCurrentLayoutPerMode(string modeId) + { + // Save Project Current Layout + SaveWindowLayout(FileUtil.CombinePaths(Directory.GetCurrentDirectory(), GetProjectLayoutPerMode(modeId))); // Save Global Last Layout - SaveWindowLayout(Path.Combine(layoutsPreferencesPath, kLastLayoutName)); + SaveWindowLayout(FileUtil.CombinePaths(layoutsPreferencesPath, modeId, kLastLayoutName)); } - private static string GetDefaultLayoutPath() + internal static string GetCurrentLayoutPath() { - return Path.Combine(layoutsPreferencesPath, kDefaultLayoutName); + var currentLayoutPath = ProjectLayoutPath; + + // Make sure we have a current layout file created + if (!File.Exists(ProjectLayoutPath)) + { + currentLayoutPath = GetDefaultLayoutPath(); + if (File.Exists(LastLayoutPath)) + { + // First we try to load the last layout (per mode) + currentLayoutPath = LastLayoutPath; + } + else if (ModeService.currentId == ModeService.k_DefaultModeId) + { + // Backward compatibility check: + // Old non mode Library\CurrentLayout.dwlt + if (File.Exists(kOldCurrentLayoutPath)) + { + currentLayoutPath = kOldCurrentLayoutPath; + } + else + { + // Older non mode \__Current__.dwlt + if (File.Exists(OldGlobalLayoutPath)) + { + currentLayoutPath = OldGlobalLayoutPath; + } + } + } + } + + return currentLayoutPath; + } + + internal static string GetDefaultLayoutPath() + { + return Path.Combine(layoutsModePreferencesPath, kDefaultLayoutName); + } + + internal static string GetProjectLayoutPerMode(string modeId) + { + return $"Library/CurrentLayout-{modeId}.dwlt"; } private static void InitializeLayoutPreferencesFolder() @@ -93,26 +132,40 @@ private static void InitializeLayoutPreferencesFolder() if (!Directory.Exists(layoutsPreferencesPath)) Directory.CreateDirectory(layoutsPreferencesPath); - // Make sure we have a window layouts preferences folder - if (!Directory.Exists(layoutsDefaultModePreferencesPath)) + if (!Directory.Exists(layoutsModePreferencesPath)) { - // If not copy the standard set of window layouts to the preferences folder - FileUtil.CopyFileOrDirectory(layoutResourcesPath, layoutsDefaultModePreferencesPath); - var defaultModeUserLayouts = Directory.GetFiles(layoutsPreferencesPath, "*.wlt"); - foreach (var layoutPath in defaultModeUserLayouts) + // Make sure we have a valid default mode folder initialized with the proper default layouts. + if (layoutsDefaultModePreferencesPath == layoutsModePreferencesPath) + { + // Backward compatibility: if the default layout folder doesn't exists but some layouts have been + // saved be sure to copy them to the "default layout per mode folder". + FileUtil.CopyFileOrDirectory(layoutResourcesPath, layoutsDefaultModePreferencesPath); + var defaultModeUserLayouts = Directory.GetFiles(layoutsPreferencesPath, "*.wlt"); + foreach (var layoutPath in defaultModeUserLayouts) + { + var fileName = Path.GetFileName(layoutPath); + var dst = Path.Combine(layoutsDefaultModePreferencesPath, fileName); + if (!File.Exists(dst)) + FileUtil.CopyFileIfExists(layoutPath, dst, false); + } + } + else { - var fileName = Path.GetFileName(layoutPath); - var dst = Path.Combine(layoutsDefaultModePreferencesPath, fileName); - if (!File.Exists(dst)) - FileUtil.CopyFileIfExists(layoutPath, dst, false); + Directory.CreateDirectory(layoutsModePreferencesPath); } } // Make sure we have the default layout file in the preferences folder if (!File.Exists(defaultLayoutPath)) { + var defaultModeLayoutPath = ModeService.GetDefaultModeLayout(); + if (!File.Exists(defaultModeLayoutPath)) + { + // No mode default layout, use the editor_resources Default: + defaultModeLayoutPath = Path.Combine(layoutResourcesPath, kDefaultLayoutName); + } // If not copy our default file to the preferences folder - FileUtil.CopyFileOrDirectory(Path.Combine(layoutResourcesPath, kDefaultLayoutName), defaultLayoutPath); + FileUtil.CopyFileOrDirectory(defaultModeLayoutPath, defaultLayoutPath); } Debug.Assert(File.Exists(defaultLayoutPath)); } @@ -684,7 +737,7 @@ public static bool LoadWindowLayout(string path, bool newProjectLayoutWasCreated continue; } - // Host views that donot hold any containers are not desirable at this stage + // Host views that do not hold any containers are not desirable at this stage HostView hostview = o as HostView; if (hostview != null && hostview.actualView == null) { @@ -830,11 +883,11 @@ internal static void LoadDefaultLayout() { InitializeLayoutPreferencesFolder(); - FileUtil.DeleteFileOrDirectory(kCurrentLayoutPath); - FileUtil.CopyFileOrDirectory(GetDefaultLayoutPath(), kCurrentLayoutPath); - Debug.Assert(File.Exists(kCurrentLayoutPath)); + FileUtil.DeleteFileOrDirectory(ProjectLayoutPath); + FileUtil.CopyFileOrDirectory(GetDefaultLayoutPath(), ProjectLayoutPath); + Debug.Assert(File.Exists(ProjectLayoutPath)); - LoadWindowLayout(kCurrentLayoutPath, true); + LoadWindowLayout(ProjectLayoutPath, true); } public static void CloseWindows() @@ -934,19 +987,27 @@ public static void SaveWindowLayout(string path) all.Add(w); } - InternalEditorUtility.SaveToSerializedFileAndForget(all.ToArray(typeof(UnityObject)) as UnityObject[], path, true); + var parentLayoutFolder = Path.GetDirectoryName(path); + if (!String.IsNullOrEmpty(parentLayoutFolder)) + { + if (!Directory.Exists(parentLayoutFolder)) + Directory.CreateDirectory(parentLayoutFolder); + InternalEditorUtility.SaveToSerializedFileAndForget(all.ToArray(typeof(UnityObject)) as UnityObject[], path, true); + } } - internal static MainView FindMainView() + internal static View FindMainView() { - var mainViews = Resources.FindObjectsOfTypeAll(); - if (mainViews.Length == 0) + UnityEngine.Object[] containers = Resources.FindObjectsOfTypeAll(typeof(ContainerWindow)); + foreach (ContainerWindow window in containers) { - Debug.LogError("No Main View found!"); - return null; + if (window.showMode == ShowMode.MainWindow) + return window.rootView; } - return mainViews[0]; + + Debug.LogError("No Main View found!"); + return null; } public static void SaveGUI() @@ -970,17 +1031,13 @@ public static void RevertFactorySettings(bool quitOnCancel = true) return; } + ModeService.ChangeModeById("default"); FileUtil.DeleteFileOrDirectory(layoutsPreferencesPath); - FileUtil.DeleteFileOrDirectory(kCurrentLayoutPath); + FileUtil.DeleteFileOrDirectory(ProjectLayoutPath); LoadDefaultWindowPreferences(); ShortcutIntegration.instance.RebuildShortcuts(); } - - internal static string layoutsPreferencesPath => FileUtil.CombinePaths(InternalEditorUtility.unityPreferencesFolder, "Layouts"); - internal static string layoutsModePreferencesPath => FileUtil.CombinePaths(layoutsPreferencesPath, ModeService.currentId); - internal static string layoutsDefaultModePreferencesPath => FileUtil.CombinePaths(layoutsPreferencesPath, "default"); - internal static string layoutsProjectPath => Directory.GetCurrentDirectory() + "/Library"; } [EditorWindowTitle(title = "Save Layout")] diff --git a/Editor/Mono/GUIView.cs b/Editor/Mono/GUIView.cs index 60de9e8e7e..3d141c2db1 100644 --- a/Editor/Mono/GUIView.cs +++ b/Editor/Mono/GUIView.cs @@ -17,6 +17,24 @@ namespace UnityEditor [StructLayout(LayoutKind.Sequential)] internal partial class GUIView : View { + // Case 1183719 - The delegate getEditorShader is being reset upon domain reload and InitializeOnLoad is not rerun + // Hence a static constructor to Initialize the Delegate. EditorShaderLoader is still needed for Batch mode where GUIView may not be created + static GUIView() + { + // TODO: Remove this once case 1148851 has been fixed. + UnityEngine.UIElements.UIR.UIRenderDevice.getEditorShader = () => EditorShader; + } + + [InitializeOnLoad] + static class EditorShaderLoader + { + static EditorShaderLoader() + { + // TODO: Remove this once case 1148851 has been fixed. + UnityEngine.UIElements.UIR.UIRenderDevice.getEditorShader = () => EditorShader; + } + } + internal static event Action positionChanged = null; Panel m_Panel = null; diff --git a/Editor/Mono/GameView/GameView.cs b/Editor/Mono/GameView/GameView.cs index 0992ae1cad..cadd717a1c 100644 --- a/Editor/Mono/GameView/GameView.cs +++ b/Editor/Mono/GameView/GameView.cs @@ -53,7 +53,7 @@ float minScale { var clampedMinScale = Mathf.Min(kMinScale, ScaleThatFitsTargetInView(targetSize, viewInWindow.size)); if (m_LowResolutionForAspectRatios[(int)currentSizeGroupType] && currentGameViewSize.sizeType == GameViewSizeType.AspectRatio) - clampedMinScale = Mathf.Max(clampedMinScale, EditorGUIUtility.pixelsPerPoint); + clampedMinScale = Mathf.Max(clampedMinScale, Mathf.Floor(EditorGUIUtility.pixelsPerPoint)); return clampedMinScale; } } @@ -312,6 +312,7 @@ void InitializeZoomArea() public void OnEnable() { + prevSizeGroupType = (int)currentSizeGroupType; titleContent = GetLocalizedTitleContent(); UpdateZoomAreaAndParent(); dontClearBackground = true; diff --git a/Editor/Mono/GameView/GameViewSizes.cs b/Editor/Mono/GameView/GameViewSizes.cs index c43dd0b614..d3dfab7c75 100644 --- a/Editor/Mono/GameView/GameViewSizes.cs +++ b/Editor/Mono/GameView/GameViewSizes.cs @@ -269,7 +269,7 @@ internal static bool DefaultLowResolutionSettingForStandalone() case BuildTarget.StandaloneOSX: return !PlayerSettings.macRetinaSupport; // if retina support enabled -> expecting LowRes setting disabled by default default: - return true; + return GUIUtility.pixelsPerPoint <= 1.0f; } } diff --git a/Editor/Mono/HandleUtility.cs b/Editor/Mono/HandleUtility.cs index b104277004..b61ad6f5cc 100644 --- a/Editor/Mono/HandleUtility.cs +++ b/Editor/Mono/HandleUtility.cs @@ -132,6 +132,11 @@ public static float DistanceToLine(Vector3 p1, Vector3 p2) Vector2 point = Event.current.mousePosition; + return DistanceToLineInternal(point, p1, p2); + } + + internal static float DistanceToLineInternal(Vector3 point, Vector3 p1, Vector3 p2) + { float retval = DistancePointLine(point, p1, p2); if (retval < 0) retval = 0.0f; @@ -323,35 +328,83 @@ public static Vector3 ClosestPointToDisc(Vector3 center, Vector3 normal, float r return ClosestPointToArc(center, normal, tangent, 360, radius); } + static Vector3[] m_ArcPointsBuffer = new Vector3[60]; + // Pixel distance from mouse pointer to a 3D section of a disc. public static float DistanceToArc(Vector3 center, Vector3 normal, Vector3 from, float angle, float radius) { - Vector3[] points = new Vector3[60]; - Handles.SetDiscSectionPoints(points, center, normal, from, angle, radius); - return DistanceToPolyLine(points); + Handles.SetDiscSectionPoints(m_ArcPointsBuffer, center, normal, from, angle, radius); + return DistanceToPolyLineOnPlane(m_ArcPointsBuffer, center, normal); } // Get the nearest 3D point. public static Vector3 ClosestPointToArc(Vector3 center, Vector3 normal, Vector3 from, float angle, float radius) { - Vector3[] points = new Vector3[60]; - Handles.SetDiscSectionPoints(points, center, normal, from, angle, radius); - return ClosestPointToPolyLine(points); + Handles.SetDiscSectionPoints(m_ArcPointsBuffer, center, normal, from, angle, radius); + return ClosestPointToPolyLine(m_ArcPointsBuffer); } // Pixel distance from mouse pointer to a polyline. public static float DistanceToPolyLine(params Vector3[] points) { - float dist = DistanceToLine(points[0], points[1]); + Camera cam = Camera.current; + Matrix4x4 handlesMatrix = Handles.matrix; + float screenHeight = Screen.height; + + Vector2 point = Event.current.mousePosition; + Vector3 p1 = WorldToGUIPointWithDepth(points[0], cam, handlesMatrix, screenHeight); + Vector3 p2 = WorldToGUIPointWithDepth(points[1], cam, handlesMatrix, screenHeight); + float dist = DistanceToLineInternal(point, p1, p2); + for (int i = 2; i < points.Length; i++) { - float d = DistanceToLine(points[i - 1], points[i]); + p1 = p2; + p2 = WorldToGUIPointWithDepth(points[i], cam, handlesMatrix, screenHeight); + + float d = DistanceToLineInternal(point, p1, p2); if (d < dist) dist = d; } return dist; } + // Pixel distance from mouse pointer to a polyline on a 2D plane. + internal static float DistanceToPolyLineOnPlane(Vector3[] points, Vector3 center, Vector3 normal) + { + Plane p = new Plane(normal, center); + + Vector2 point = Event.current.mousePosition; + Ray r = GUIPointToWorldRay(point); + + float enter; + if (!p.Raycast(r, out enter)) + return DistanceToPolyLine(points); + + Vector3 intersect = r.GetPoint(enter); + + Vector3 p1 = points[0]; + Vector3 p2 = points[1]; + float dist = DistanceToLineInternal(intersect, p1, p2); + + Vector3 s1 = Vector3.zero, s2 = Vector3.zero; + + for (int i = 2; i < points.Length; i++) + { + p1 = p2; + p2 = points[i]; + + float d = DistanceToLineInternal(intersect, p1, p2); + if (d < dist) + { + dist = d; + s1 = p1; + s2 = p2; + } + } + + return DistanceToLineInternal(point, WorldToGUIPoint(s1), WorldToGUIPoint(s2)); + } + // Get the nearest 3D point. public static Vector3 ClosestPointToPolyLine(params Vector3[] vertices) { @@ -469,12 +522,19 @@ public static Vector2 WorldToGUIPoint(Vector3 world) // Convert world space point to a 2D GUI position. public static Vector3 WorldToGUIPointWithDepth(Vector3 world) { - world = Handles.matrix.MultiplyPoint(world); - Camera cam = Camera.current; - if (cam) + return WorldToGUIPointWithDepth(world, Camera.current, Handles.matrix, Screen.height); + } + + // Convert world space point to a 2D GUI position. + // Use this version in critical loops. + internal static Vector3 WorldToGUIPointWithDepth(Vector3 world, Camera camera, Matrix4x4 matrixHandles, float screenHeight) + { + world = matrixHandles.MultiplyPoint(world); + + if (camera) { - Vector3 pos = cam.WorldToScreenPoint(world); - pos.y = Screen.height - pos.y; + Vector3 pos = camera.WorldToScreenPoint(world); + pos.y = screenHeight - pos.y; Vector2 points = EditorGUIUtility.PixelsToPoints(pos); points = GUIClip.Clip(points); return new Vector3(points.x, points.y, pos.z); diff --git a/Editor/Mono/HostView.cs b/Editor/Mono/HostView.cs index 787e6bc10e..f7bbca64f3 100644 --- a/Editor/Mono/HostView.cs +++ b/Editor/Mono/HostView.cs @@ -4,10 +4,12 @@ using UnityEngine; using System; +using System.Collections.Generic; using System.Reflection; using UnityEditor.UIElements.Debugger; using UnityEngine.UIElements; using System.Linq; +using UnityEditor.ShortcutManagement; namespace UnityEditor { @@ -190,23 +192,43 @@ protected override void OnDestroy() base.OnDestroy(); } - protected Type[] GetPaneTypes() + private static readonly Type[] k_PaneTypes = + { + typeof(SceneView), + typeof(GameView), + typeof(InspectorWindow), + typeof(SceneHierarchyWindow), + typeof(ProjectBrowser), + typeof(ProfilerWindow), + typeof(AnimationWindow) + }; + + private static IEnumerable GetCurrentModePaneTypes(string modePaneTypeSectionName) + { + var modePaneTypes = ModeService.GetModeDataSectionList(ModeService.currentIndex, modePaneTypeSectionName); + var editorWindowTypes = TypeCache.GetTypesDerivedFrom(); + foreach (var paneTypeName in modePaneTypes) + { + var paneType = editorWindowTypes.FirstOrDefault(t => t.Name.EndsWith(paneTypeName)); + if (paneType != null) + yield return paneType; + else + Debug.LogWarning($"Cannot find editor window pane type {paneTypeName} for editor mode {ModeService.currentId}."); + } + } + + private static IEnumerable GetDefaultPaneTypes() { const string k_PaneTypesSectionName = "pane_types"; if (!ModeService.HasSection(ModeService.currentIndex, k_PaneTypesSectionName)) - return new[] - { - typeof(SceneView), - typeof(GameView), - typeof(InspectorWindow), - typeof(SceneHierarchyWindow), - typeof(ProjectBrowser), - typeof(ProfilerWindow), - typeof(AnimationWindow) - }; + return k_PaneTypes; + return GetCurrentModePaneTypes(k_PaneTypesSectionName); + } - var modePaneTypes = ModeService.GetModeDataSectionList(ModeService.currentIndex, k_PaneTypesSectionName).ToArray(); - return EditorAssemblies.SubclassesOf(typeof(EditorWindow)).Where(t => modePaneTypes.Any(mpt => t.Name.EndsWith(mpt))).ToArray(); + protected IEnumerable GetPaneTypes() + { + foreach (var paneType in GetDefaultPaneTypes()) + yield return paneType; } // Messages sent by Unity to editor windows today. @@ -289,18 +311,6 @@ static class HostViewStyles public void InvokeOnGUI(Rect onGUIPosition, Rect viewRect) { - // Handle window reloading. - if (Unsupported.IsDeveloperMode() && - actualView != null && - Event.current.type == EventType.KeyUp && Event.current.keyCode == KeyCode.F5) - { - if (Event.current.control) - DebugWindow(actualView); - else - Reload(actualView); - return; - } - DoWindowDecorationStart(); BeginOffsetArea(viewRect, GUIContent.none, "TabWindowBackground"); @@ -310,7 +320,8 @@ public void InvokeOnGUI(Rect onGUIPosition, Rect viewRect) bool isExitGUIException = false; try { - using (new PerformanceTracker(actualView.GetType().Name + ".OnGUI." + Event.current.type)) + var viewName = actualView != null ? actualView.GetType().Name : GetType().Name; + using (new PerformanceTracker(viewName + ".OnGUI." + Event.current.type)) { Invoke("OnGUI"); } @@ -526,15 +537,6 @@ private void Inspect(object userData) Selection.activeObject = (UnityEngine.Object)userData; } - internal void DebugWindow(object userData) - { - EditorWindow window = userData as EditorWindow; - if (window == null) - return; - - UIElementsDebugger.OpenAndInspectWindow(window); - } - internal void Reload(object userData) { EditorWindow window = userData as EditorWindow; @@ -623,7 +625,7 @@ void UpdatePlayModeColor(Color newColorToUse) UIElementsUtility.editorPlayModeTintColor = newColorToUse; // Make sure to dirty the right imgui container in this HostView (and all its children / parents) - // The MarkDirtyRepaint() function is dirtying the element itself and its parent, but not the children explicitely. + // The MarkDirtyRepaint() function is dirtying the element itself and its parent, but not the children explicitly. // ... and in the repaint function, it check for the current rendered element, not the parent. // Since the HostView "hosts" an IMGUIContainer or any VisualElement, we have to make sure to dirty everything here. PropagateDirtyRepaint(visualTree); @@ -651,5 +653,24 @@ protected void ClearBackground() EditorGUIUtility.kViewBackgroundColor); backgroundValid = true; } + + protected void AddUIElementsDebuggerToMenu(GenericMenu menu) + { + var itemContent = UIElementsDebugger.WindowName; + var shortcut = ShortcutIntegration.instance.directory.FindShortcutEntry(UIElementsDebugger.k_WindowPath); + if (shortcut != null && shortcut.combinations.Any()) + itemContent += $" {KeyCombination.SequenceToMenuString(shortcut.combinations)}"; + + menu.AddItem(EditorGUIUtility.TextContent(itemContent), false, DebugWindow, actualView); + } + + private void DebugWindow(object userData) + { + EditorWindow window = userData as EditorWindow; + if (window == null) + return; + + UIElementsDebugger.OpenAndInspectWindow(window); + } } } diff --git a/Editor/Mono/ImportSettings/AnimationClipInfoProperties.cs b/Editor/Mono/ImportSettings/AnimationClipInfoProperties.cs index b98bc4aa54..887621b790 100644 --- a/Editor/Mono/ImportSettings/AnimationClipInfoProperties.cs +++ b/Editor/Mono/ImportSettings/AnimationClipInfoProperties.cs @@ -62,6 +62,11 @@ SerializedProperty Get(string property) public SerializedProperty bodyMaskProperty { get { return Get("bodyMask"); } } public SerializedProperty transformMaskProperty { get { return Get("transformMask"); } } + public void ApplyModifiedProperties() + { + m_Property.serializedObject.ApplyModifiedProperties(); + } + public bool MaskNeedsUpdating() { AvatarMask mask = maskSource; diff --git a/Editor/Mono/ImportSettings/IHVImageFormatImporterInspector.cs b/Editor/Mono/ImportSettings/IHVImageFormatImporterInspector.cs index d7984454a5..88c0808163 100644 --- a/Editor/Mono/ImportSettings/IHVImageFormatImporterInspector.cs +++ b/Editor/Mono/ImportSettings/IHVImageFormatImporterInspector.cs @@ -29,7 +29,7 @@ internal class Styles public static readonly GUIContent sRGBTexture = EditorGUIUtility.TrTextContent("sRGB (Color Texture)", "Texture content is stored in gamma space. Non-HDR color textures should enable this flag (except if used for IMGUI)."); public static readonly GUIContent wrapMode = EditorGUIUtility.TrTextContent("Wrap Mode"); public static readonly GUIContent filterMode = EditorGUIUtility.TrTextContent("Filter Mode"); - public static readonly GUIContent streamingMipmaps = EditorGUIUtility.TrTextContent("Streaming Mip Maps", "Only load larger mip maps as needed to render the current game cameras."); + public static readonly GUIContent streamingMipmaps = EditorGUIUtility.TrTextContent("Streaming Mipmaps", "Only load larger mipmaps as needed to render the current game cameras."); public static readonly GUIContent streamingMipmapsPriority = EditorGUIUtility.TrTextContent("Mip Map Priority", "Mip map streaming priority when there's contention for resources. Positive numbers represent higher priority. Valid range is -128 to 127."); public static readonly int[] filterModeValues = diff --git a/Editor/Mono/ImportSettings/TextureImportPlatformSettings.cs b/Editor/Mono/ImportSettings/TextureImportPlatformSettings.cs index 3b250e4945..74bc7e5407 100644 --- a/Editor/Mono/ImportSettings/TextureImportPlatformSettings.cs +++ b/Editor/Mono/ImportSettings/TextureImportPlatformSettings.cs @@ -412,6 +412,8 @@ public void Apply() imp.SetPlatformTextureSettings(platformSettings); } + + m_HasChanged = false; } public static readonly int[] kAndroidETC2FallbackOverrideValues = diff --git a/Editor/Mono/ImportSettings/TextureImporterInspector.cs b/Editor/Mono/ImportSettings/TextureImporterInspector.cs index 3a4c5614e3..b768d844eb 100644 --- a/Editor/Mono/ImportSettings/TextureImporterInspector.cs +++ b/Editor/Mono/ImportSettings/TextureImporterInspector.cs @@ -225,7 +225,7 @@ internal class Styles public readonly GUIContent[] cubemapOptions = { EditorGUIUtility.TrTextContent("Auto"), - EditorGUIUtility.TrTextContent("6 Frames Layout (Cubic Environment)", "Texture contains 6 images arranged in one of the standard cubemap layouts - cross or sequence (+x,-x, +y, -y, +z, -z). Texture can be in vertical or horizontal orientation."), + EditorGUIUtility.TrTextContent("6 Frames Layout (Cubic Environment)", "Texture contains 6 images arranged in one of the standard cubemap layouts - cross or sequence (+x, -x, +y, -y, +z, -z). Texture can be in vertical or horizontal orientation."), EditorGUIUtility.TrTextContent("Latitude-Longitude Layout (Cylindrical)", "Texture contains an image of a ball unwrapped such that latitude and longitude are mapped to horizontal and vertical dimensions (as on a globe)."), EditorGUIUtility.TrTextContent("Mirrored Ball (Spheremap)", "Texture contains an image of a mirrored ball.") }; @@ -258,7 +258,7 @@ internal class Styles public readonly GUIContent mipmapFadeOutToggle = EditorGUIUtility.TrTextContent("Fadeout Mip Maps"); public readonly GUIContent mipmapFadeOut = EditorGUIUtility.TrTextContent("Fade Range"); public readonly GUIContent readWrite = EditorGUIUtility.TrTextContent("Read/Write Enabled", "Enable to be able to access the raw pixel data from code."); - public readonly GUIContent streamingMipmaps = EditorGUIUtility.TrTextContent("Streaming Mip Maps", "Only load larger mip maps as needed to render the current game cameras. Requires texture streaming to be enabled in quality settings."); + public readonly GUIContent streamingMipmaps = EditorGUIUtility.TrTextContent("Streaming Mipmaps", "Only load larger mipmaps as needed to render the current game cameras. Requires texture streaming to be enabled in quality settings."); public readonly GUIContent streamingMipmapsPriority = EditorGUIUtility.TrTextContent("Mip Map Priority", "Mip map streaming priority when there's contention for resources. Positive numbers represent higher priority. Valid range is -128 to 127."); public readonly GUIContent alphaSource = EditorGUIUtility.TrTextContent("Alpha Source", "How is the alpha generated for the imported texture."); @@ -298,7 +298,7 @@ internal class Styles EditorGUIUtility.TrTextContent("Box"), EditorGUIUtility.TrTextContent("Kaiser"), }; - public readonly GUIContent npot = EditorGUIUtility.TrTextContent("Non Power of 2", "How non-power-of-two textures are scaled on import."); + public readonly GUIContent npot = EditorGUIUtility.TrTextContent("Non-Power of 2", "How non-power-of-two textures are scaled on import."); public readonly GUIContent generateCubemap = EditorGUIUtility.TrTextContent("Generate Cubemap"); public readonly GUIContent compressionQuality = EditorGUIUtility.TrTextContent("Compressor Quality"); @@ -351,7 +351,7 @@ internal class Styles public readonly GUIContent showAdvanced = EditorGUIUtility.TrTextContent("Advanced", "Show advanced settings."); public readonly GUIContent psdRemoveMatte = EditorGUIUtility.TrTextContent("Remove Matte (PSD)", "Enable special processing for PSD that has transparency, as color pixels will be tweaked (blended with white color)."); - public readonly GUIContent psdRemoveMatteWarning = EditorGUIUtility.TrTextContent("If you have PSD with transparency, colors will be tweaked by blending them with white color. Matte removal refers to our attempts to undo that, and this is deprecated."); + public readonly GUIContent psdRemoveMatteInfo = EditorGUIUtility.TrTextContent("If you have PSD with transparency, colors will be tweaked by blending them with white color. Matte removal refers to our attempts to undo that."); public readonly GUIContent psdRemoveMatteURLButton = EditorGUIUtility.TrTextContent("How to handle PSD with alpha"); public readonly string psdRemoveMatteURL = "https://docs.unity3d.com/Manual/HOWTO-alphamaps.html"; @@ -916,7 +916,7 @@ void AlphaHandlingGUI(TextureInspectorGUIElement guiElements) if (m_PSDRemoveMatte.boolValue) { GUILayout.BeginVertical(); - EditorGUILayout.HelpBox(s_Styles.psdRemoveMatteWarning.text, MessageType.Warning, true); + EditorGUILayout.HelpBox(s_Styles.psdRemoveMatteInfo.text, MessageType.Info, true); if (EditorGUILayout.LinkLabel(s_Styles.psdRemoveMatteURLButton)) Application.OpenURL(s_Styles.psdRemoveMatteURL); GUILayout.EndVertical(); diff --git a/Editor/Mono/Inspector/AddComponent/AddComponentDataSource.cs b/Editor/Mono/Inspector/AddComponent/AddComponentDataSource.cs index e749dc8cf2..28ca08592b 100644 --- a/Editor/Mono/Inspector/AddComponent/AddComponentDataSource.cs +++ b/Editor/Mono/Inspector/AddComponent/AddComponentDataSource.cs @@ -47,8 +47,7 @@ protected AdvancedDropdownItem RebuildTree() var path = paths[j]; if (j == paths.Length - 1) { - var element = new ComponentDropdownItem(path, menuPath, menu.Value); - element.localizedName = L10n.Tr(path); + var element = new ComponentDropdownItem(path, L10n.Tr(path), menuPath, menu.Value); parent.AddChild(element); m_SearchableElements.Add(element); continue; @@ -56,16 +55,14 @@ protected AdvancedDropdownItem RebuildTree() var group = (ComponentDropdownItem)parent.children.SingleOrDefault(c => c.name == path); if (group == null) { - group = new ComponentDropdownItem(path); - group.localizedName = L10n.Tr(path); + group = new ComponentDropdownItem(path, L10n.Tr(path)); parent.AddChild(group); } parent = group; } } root = root.children.Single(); - var newScript = new ComponentDropdownItem("New script"); - newScript.localizedName = L10n.Tr("New script"); + var newScript = new ComponentDropdownItem("New script", L10n.Tr("New script")); newScript.AddChild(new NewScriptDropdownItem()); root.AddChild(newScript); return root; @@ -141,8 +138,7 @@ protected override AdvancedDropdownItem Search(string searchString) } if (searchTree != null) { - var addNewScriptGroup = new ComponentDropdownItem("New script"); - addNewScriptGroup.name = L10n.Tr("New script"); + var addNewScriptGroup = new ComponentDropdownItem("New script", L10n.Tr("New script")); m_State.SetSelectedIndex(addNewScriptGroup, 0); var addNewScript = new NewScriptDropdownItem(); addNewScript.className = searchString; diff --git a/Editor/Mono/Inspector/AddComponent/AddComponentGUI.cs b/Editor/Mono/Inspector/AddComponent/AddComponentGUI.cs index 94ddbd9380..440a03a23f 100644 --- a/Editor/Mono/Inspector/AddComponent/AddComponentGUI.cs +++ b/Editor/Mono/Inspector/AddComponent/AddComponentGUI.cs @@ -33,7 +33,7 @@ internal override void DrawItem(AdvancedDropdownItem item, string name, Texture2 { if (hasSearch && item is ComponentDropdownItem) { - name = ((ComponentDropdownItem)item).searchableName; + name = ((ComponentDropdownItem)item).searchableNameLocalized; } base.DrawItem(item, name, icon, enabled, drawArrow, selected, hasSearch); return; diff --git a/Editor/Mono/Inspector/AddComponent/ComponentDropdownItem.cs b/Editor/Mono/Inspector/AddComponent/ComponentDropdownItem.cs index e66b2ffb12..005031acf6 100644 --- a/Editor/Mono/Inspector/AddComponent/ComponentDropdownItem.cs +++ b/Editor/Mono/Inspector/AddComponent/ComponentDropdownItem.cs @@ -16,6 +16,10 @@ internal class ComponentDropdownItem : AdvancedDropdownItem private string m_SearchableNameLocalized; private string m_SearchableName; + internal override string displayName + { + get { return m_LocalizedName; } + } public string searchableName { get @@ -41,7 +45,6 @@ public string searchableNameLocalized public string localizedName { get { return m_LocalizedName ?? name; } - set { m_LocalizedName = value; } } public string menuPath => m_MenuPath; @@ -50,8 +53,16 @@ public ComponentDropdownItem(string name) : base(name) { } - public ComponentDropdownItem(string name, string menuPath, string command) : base(name) + public ComponentDropdownItem(string name, string localized) : base(name) { + m_LocalizedName = localized; + m_SearchableName = name; + m_SearchableNameLocalized = localized; + } + + public ComponentDropdownItem(string name, string localized, string menuPath, string command) : base(name) + { + m_LocalizedName = localized; m_MenuPath = menuPath; m_IsLegacy = menuPath.Contains("Legacy"); @@ -66,10 +77,11 @@ public ComponentDropdownItem(string name, string menuPath, string command) : bas else { var classId = int.Parse(command); - base.name = localizedName; + base.name = name; base.icon = AssetPreview.GetMiniTypeThumbnailFromClassID(classId); } m_SearchableName = name; + m_SearchableNameLocalized = localized; if (m_IsLegacy) { m_SearchableName += " (Legacy)"; diff --git a/Editor/Mono/Inspector/AddComponent/NewScriptDropdownItem.cs b/Editor/Mono/Inspector/AddComponent/NewScriptDropdownItem.cs index 94d99b39e9..c8d0d0d987 100644 --- a/Editor/Mono/Inspector/AddComponent/NewScriptDropdownItem.cs +++ b/Editor/Mono/Inspector/AddComponent/NewScriptDropdownItem.cs @@ -27,9 +27,8 @@ public string className } public NewScriptDropdownItem() - : base("New Script") + : base("New Script", L10n.Tr("New Script")) { - localizedName = L10n.Tr("New Script"); } internal bool CanCreate() diff --git a/Editor/Mono/Inspector/AdvancedDropdown/AdvancedDropdownGUI.cs b/Editor/Mono/Inspector/AdvancedDropdown/AdvancedDropdownGUI.cs index 2aad0882c5..443f86572d 100644 --- a/Editor/Mono/Inspector/AdvancedDropdown/AdvancedDropdownGUI.cs +++ b/Editor/Mono/Inspector/AdvancedDropdown/AdvancedDropdownGUI.cs @@ -102,7 +102,7 @@ internal virtual void DrawLineSeparator() internal void DrawHeader(AdvancedDropdownItem group, Action backButtonPressed, bool hasParent) { - var content = GUIContent.Temp(group.name, group.icon); + var content = GUIContent.Temp(group.displayName, group.icon); m_HeaderRect = GUILayoutUtility.GetRect(content, Styles.header, GUILayout.ExpandWidth(true)); if (Event.current.type == EventType.Repaint) diff --git a/Editor/Mono/Inspector/AdvancedDropdown/AdvancedDropdownItem.cs b/Editor/Mono/Inspector/AdvancedDropdown/AdvancedDropdownItem.cs index 9eeaf4fcae..49dfa9ddc5 100644 --- a/Editor/Mono/Inspector/AdvancedDropdown/AdvancedDropdownItem.cs +++ b/Editor/Mono/Inspector/AdvancedDropdown/AdvancedDropdownItem.cs @@ -23,6 +23,11 @@ public string name set { m_Name = value; } } + internal virtual string displayName + { + get { return m_Name; } + } + public Texture2D icon { get { return m_Icon; } diff --git a/Editor/Mono/Inspector/AdvancedDropdown/AdvancedDropdownWindow.cs b/Editor/Mono/Inspector/AdvancedDropdown/AdvancedDropdownWindow.cs index 919dc589f6..22f9450fc0 100644 --- a/Editor/Mono/Inspector/AdvancedDropdown/AdvancedDropdownWindow.cs +++ b/Editor/Mono/Inspector/AdvancedDropdown/AdvancedDropdownWindow.cs @@ -411,7 +411,7 @@ private void DrawList(AdvancedDropdownItem item) } else { - m_Gui.DrawItem(child, child.name, child.icon, child.enabled, child.children.Any(), selected, hasSearch); + m_Gui.DrawItem(child, child.displayName, child.icon, child.enabled, child.children.Any(), selected, hasSearch); } var r = GUILayoutUtility.GetLastRect(); diff --git a/Editor/Mono/Inspector/AnimationClipEditor.cs b/Editor/Mono/Inspector/AnimationClipEditor.cs index 82dbb67f53..083203825a 100644 --- a/Editor/Mono/Inspector/AnimationClipEditor.cs +++ b/Editor/Mono/Inspector/AnimationClipEditor.cs @@ -3,11 +3,8 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using UnityEngine; -using UnityEditor; using UnityEditor.Animations; -using UnityEditor.AnimatedValues; using System; -using System.Reflection; using System.Collections.Generic; using System.Linq; using Object = UnityEngine.Object; @@ -48,7 +45,7 @@ private static class Styles public static GUIContent HasAdditiveReferencePose = EditorGUIUtility.TrTextContent("Additive Reference Pose", "Enable to define the additive reference pose frame."); public static GUIContent AdditiveReferencePoseFrame = EditorGUIUtility.TrTextContent("Pose Frame", "Pose Frame."); - public static GUIContent LoopTime = EditorGUIUtility.TrTextContent("Loop Time", "Enable to make the animation plays through and then restarts when the end is reached."); + public static GUIContent LoopTime = EditorGUIUtility.TrTextContent("Loop Time", "Enable to make the animation play through and then restart when the end is reached."); public static GUIContent LoopPose = EditorGUIUtility.TrTextContent("Loop Pose", "Enable to make the animation loop seamlessly."); public static GUIContent LoopCycleOffset = EditorGUIUtility.TrTextContent("Cycle Offset", "Offset to the cycle of a looping animation, if we want to start it at a different time."); public static GUIContent RootTransformRotation = EditorGUIUtility.TrTextContent("Root Transform Rotation"); @@ -1674,6 +1671,7 @@ public void EventLineContextMenuAdd(object obj) EventModificationContextMenuObject context = (EventModificationContextMenuObject)obj; context.m_Info.AddEvent(context.m_Time); + context.m_Info.ApplyModifiedProperties(); SelectEvent(context.m_Info.GetEvents(), context.m_Info.GetEventCount() - 1, context.m_Info); } @@ -1693,6 +1691,7 @@ public void EventLineContextMenuDelete(object obj) { context.m_Info.RemoveEvent(context.m_Index); } + context.m_Info.ApplyModifiedProperties(); } private void CheckRectsOnMouseMove(Rect eventLineRect, AnimationEvent[] events, Rect[] hitRects) diff --git a/Editor/Mono/Inspector/AssemblyDefinitionImporterInspector.cs b/Editor/Mono/Inspector/AssemblyDefinitionImporterInspector.cs index 6e4a3ff38c..05a71a33a4 100644 --- a/Editor/Mono/Inspector/AssemblyDefinitionImporterInspector.cs +++ b/Editor/Mono/Inspector/AssemblyDefinitionImporterInspector.cs @@ -296,7 +296,9 @@ public override void OnInspectorGUI() protected override void Apply() { base.Apply(); - SaveAndUpdateAssemblyDefinitionStates(extraDataTargets.Cast().ToArray()); + // Do not write back to the asset if no asset can be found. + if (assetTarget != null) + SaveAndUpdateAssemblyDefinitionStates(extraDataTargets.Cast().ToArray()); } static void InversePlatformCompatibility(AssemblyDefinitionState state) @@ -531,10 +533,20 @@ static void LoadAssemblyDefintionState(AssemblyDefinitionState state, string pat if (asset == null) return; - var data = CustomScriptAssemblyData.FromJson(asset.text); + var data = CustomScriptAssemblyData.FromJsonNoFieldValidation(asset.text); + if (data == null) return; + try + { + data.ValidateFields(); + } + catch (Exception e) + { + Debug.LogException(e, asset); + } + state.asset = asset; state.assemblyName = data.name; state.references = new List(); @@ -547,7 +559,7 @@ static void LoadAssemblyDefintionState(AssemblyDefinitionState state, string pat // If the .asmdef has no references (true for newly created .asmdef), then use GUIDs. // Otherwise do not use GUIDs. This value might be changed below if any reference is a GUID. - state.useGUIDs = (data.references != null && data.references.Length > 0); + state.useGUIDs = (data.references == null || data.references.Length == 0); if (data.versionDefines != null) { diff --git a/Editor/Mono/Inspector/AudioClipInspector.cs b/Editor/Mono/Inspector/AudioClipInspector.cs index 4c0a30c4a4..2752e4b8d8 100644 --- a/Editor/Mono/Inspector/AudioClipInspector.cs +++ b/Editor/Mono/Inspector/AudioClipInspector.cs @@ -11,19 +11,19 @@ namespace UnityEditor internal class AudioClipInspector : Editor { private PreviewRenderUtility m_PreviewUtility; - - // Any number of AudioClip inspectors can be docked in addition to the object browser, and they are all showing and modifying the same shared state. - static AudioClipInspector m_PlayingInspector; - static AudioClip m_PlayingClip; - static bool playing { get { return m_PlayingClip != null && AudioUtil.IsClipPlaying(m_PlayingClip); } } - static bool m_bAutoPlay; - static bool m_bLoop; - + private AudioClip m_Clip; + private bool playing => s_PlayingInstance == this && m_Clip != null && AudioUtil.IsClipPlaying(m_Clip); Vector2 m_Position = Vector2.zero; - Rect m_wantedRect; + private bool m_MultiEditing; static GUIStyle s_PreButton; + static Rect s_WantedRect; + static bool s_AutoPlay; + static bool s_Loop; + static bool s_PlayFirst; + static AudioClipInspector s_PlayingInstance; + static GUIContent[] s_PlayIcons = {null, null}; static GUIContent[] s_AutoPlayIcons = {null, null}; static GUIContent[] s_LoopIcons = {null, null}; @@ -32,8 +32,10 @@ internal class AudioClipInspector : Editor private Material m_HandleLinesMaterial; - override public void OnInspectorGUI() + public override void OnInspectorGUI() { + // We can't always check this from preview methods + m_MultiEditing = targets.Length > 1; // Override with inspector that doesn't show anything } @@ -43,7 +45,8 @@ static void Init() return; s_PreButton = "preButton"; - m_bAutoPlay = EditorPrefs.GetBool("AutoPlayAudio", false); + s_AutoPlay = EditorPrefs.GetBool("AutoPlayAudio", false); + s_Loop = false; s_AutoPlayIcons[0] = EditorGUIUtility.TrIconContent("preAudioAutoPlayOff", "Turn Auto Play on"); s_AutoPlayIcons[1] = EditorGUIUtility.TrIconContent("preAudioAutoPlayOn", "Turn Auto Play off"); @@ -57,14 +60,13 @@ static void Init() public void OnDisable() { - // This check is necessary because the order of OnEnable/OnDisable varies depending on whether the inspector is embedded in the project browser or object selector. - if (m_PlayingInspector == this) + if (s_PlayingInstance == this) { AudioUtil.StopAllClips(); - m_PlayingClip = null; + s_PlayingInstance = null; } - EditorPrefs.SetBool("AutoPlayAudio", m_bAutoPlay); + EditorPrefs.SetBool("AutoPlayAudio", s_AutoPlay); if (m_PreviewUtility != null) { @@ -77,11 +79,9 @@ public void OnDisable() public void OnEnable() { - AudioUtil.StopAllClips(); - m_PlayingClip = null; - m_PlayingInspector = this; - - m_bAutoPlay = EditorPrefs.GetBool("AutoPlayAudio", false); + s_AutoPlay = EditorPrefs.GetBool("AutoPlayAudio", false); + if (s_AutoPlay) + s_PlayFirst = true; m_HandleLinesMaterial = EditorGUIUtility.LoadRequired("SceneView/HandleLines.mat") as Material; } @@ -119,64 +119,45 @@ public override void OnPreviewSettings() if (s_DefaultIcon == null) Init(); AudioClip clip = target as AudioClip; - - bool isEditingMultipleObjects = targets.Length > 1; + m_MultiEditing = targets.Length > 1; using (new EditorGUI.DisabledScope(AudioUtil.IsMovieAudio(clip))) { - bool oldAutoPlay = m_bAutoPlay; - bool newAutoPlay = PreviewGUI.CycleButton(oldAutoPlay ? 1 : 0, s_AutoPlayIcons) != 0; - if (oldAutoPlay != newAutoPlay) + using (new EditorGUI.DisabledScope(m_MultiEditing)) { - m_bAutoPlay = newAutoPlay; - InspectorWindow.RepaintAllInspectors(); + s_AutoPlay = s_AutoPlay && !m_MultiEditing; + s_AutoPlay = PreviewGUI.CycleButton(s_AutoPlay ? 1 : 0, s_AutoPlayIcons) != 0; } - bool oldLoop = m_bLoop; - bool newLoop = PreviewGUI.CycleButton(oldLoop ? 1 : 0, s_LoopIcons) != 0; - if (oldLoop != newLoop) - { - m_bLoop = newLoop; - if (playing) - AudioUtil.LoopClip(clip, newLoop); - InspectorWindow.RepaintAllInspectors(); - } + bool loop = s_Loop; + s_Loop = PreviewGUI.CycleButton(s_Loop ? 1 : 0, s_LoopIcons) != 0; + if ((loop != s_Loop) && playing) + AudioUtil.LoopClip(clip, s_Loop); - using (new EditorGUI.DisabledScope(isEditingMultipleObjects && !playing && m_PlayingInspector != this)) + using (new EditorGUI.DisabledScope(m_MultiEditing && !playing)) { - bool curPlaying = m_PlayingInspector == this && playing; - bool newPlaying = PreviewGUI.CycleButton(curPlaying ? 1 : 0, s_PlayIcons) != 0; + bool newPlaying = PreviewGUI.CycleButton(playing ? 1 : 0, s_PlayIcons) != 0; - if (newPlaying != curPlaying) + if (newPlaying != playing) { - AudioUtil.StopAllClips(); - m_PlayingClip = null; - m_PlayingInspector = null; - - if (newPlaying && !isEditingMultipleObjects) + if (newPlaying) + PlayClip(clip, 0, s_Loop); + else { - AudioUtil.PlayClip(clip, 0, m_bLoop); - m_PlayingClip = clip; - m_PlayingInspector = this; + AudioUtil.StopAllClips(); + m_Clip = null; } } } } + } - // autoplay start? - if (m_bAutoPlay && m_PlayingClip != clip && m_PlayingInspector == this && !isEditingMultipleObjects) - { - AudioUtil.StopAllClips(); - m_PlayingClip = null; - m_PlayingInspector = null; - - if (!isEditingMultipleObjects) - { - AudioUtil.PlayClip(clip, 0, m_bLoop); - m_PlayingClip = clip; - m_PlayingInspector = this; - } - } + void PlayClip(AudioClip clip, int startSample = 0, bool loop = false) + { + AudioUtil.StopAllClips(); + AudioUtil.PlayClip(clip, startSample, loop); + m_Clip = clip; + s_PlayingInstance = this; } // Passing in clip and importer separately as we're not completely done with the asset setup at the time we're asked to generate the preview. @@ -228,8 +209,6 @@ public override void OnPreviewGUI(Rect r, GUIStyle background) Event evt = Event.current; if (evt.type != EventType.Repaint && evt.type != EventType.Layout && evt.type != EventType.Used) { - int px2sample = (AudioUtil.GetSampleCount(clip) / (int)r.width); - switch (evt.type) { case EventType.MouseDrag: @@ -237,14 +216,11 @@ public override void OnPreviewGUI(Rect r, GUIStyle background) { if (r.Contains(evt.mousePosition) && !AudioUtil.IsMovieAudio(clip)) { - if (m_PlayingClip != clip || !AudioUtil.IsClipPlaying(clip)) - { - AudioUtil.StopAllClips(); - AudioUtil.PlayClip(clip, 0, m_bLoop); - m_PlayingClip = clip; - m_PlayingInspector = this; - } - AudioUtil.SetClipSamplePosition(clip, px2sample * (int)evt.mousePosition.x); + var startSample = (int)(evt.mousePosition.x * (AudioUtil.GetSampleCount(clip) / (int)r.width)); + if (!AudioUtil.IsClipPlaying(clip) || clip != m_Clip) + PlayClip(clip, startSample, s_Loop); + else + AudioUtil.SetClipSamplePosition(clip, startSample); evt.Use(); } } @@ -257,8 +233,8 @@ public override void OnPreviewGUI(Rect r, GUIStyle background) background.Draw(r, false, false, false, false); int c = AudioUtil.GetChannelCount(clip); - m_wantedRect = new Rect(r.x, r.y , r.width, r.height); - float sec2px = ((float)m_wantedRect.width / clip.length); + s_WantedRect = new Rect(r.x, r.y , r.width, r.height); + float sec2px = ((float)s_WantedRect.width / clip.length); bool previewAble = AudioUtil.HasPreview(clip) || !(AudioUtil.IsTrackerFile(clip) || AudioUtil.IsMovieAudio(clip)); if (!previewAble) @@ -284,50 +260,57 @@ public override void OnPreviewGUI(Rect r, GUIStyle background) EditorGUI.DropShadowLabel(new Rect(r.x, labelY, r.width, 20), "Can not show PCM data for this file"); } - if (m_PlayingInspector == this && m_PlayingClip == clip) + if (m_Clip == clip) { float t = AudioUtil.GetClipPosition(clip); System.TimeSpan ts = new System.TimeSpan(0, 0, 0, 0, (int)(t * 1000.0f)); - EditorGUI.DropShadowLabel(new Rect(m_wantedRect.x, m_wantedRect.y, m_wantedRect.width, 20), string.Format("Playing - {0:00}:{1:00}.{2:000}", ts.Minutes, ts.Seconds, ts.Milliseconds)); + EditorGUI.DropShadowLabel(new Rect(s_WantedRect.x, s_WantedRect.y, s_WantedRect.width, 20), string.Format("Playing - {0:00}:{1:00}.{2:000}", ts.Minutes, ts.Seconds, ts.Milliseconds)); } } else { - PreviewGUI.BeginScrollView(m_wantedRect, m_Position, m_wantedRect, "PreHorizontalScrollbar", "PreHorizontalScrollbarThumb"); + PreviewGUI.BeginScrollView(s_WantedRect, m_Position, s_WantedRect, "PreHorizontalScrollbar", "PreHorizontalScrollbarThumb"); if (Event.current.type == EventType.Repaint) { - DoRenderPreview(true, clip, AudioUtil.GetImporterFromClip(clip), m_wantedRect, 1.0f); + DoRenderPreview(true, clip, AudioUtil.GetImporterFromClip(clip), s_WantedRect, 1.0f); } for (int i = 0; i < c; ++i) { if (c > 1 && r.width > 64) { - var labelRect = new Rect(m_wantedRect.x + 5, m_wantedRect.y + (m_wantedRect.height / c) * i, 30, 20); + var labelRect = new Rect(s_WantedRect.x + 5, s_WantedRect.y + (s_WantedRect.height / c) * i, 30, 20); EditorGUI.DropShadowLabel(labelRect, "ch " + (i + 1).ToString()); } } - if (m_PlayingInspector == this && m_PlayingClip == clip) + if (m_Clip == clip) { float t = AudioUtil.GetClipPosition(clip); System.TimeSpan ts = new System.TimeSpan(0, 0, 0, 0, (int)(t * 1000.0f)); - GUI.DrawTexture(new Rect(m_wantedRect.x + (int)(sec2px * t), m_wantedRect.y, 2, m_wantedRect.height), EditorGUIUtility.whiteTexture); + GUI.DrawTexture(new Rect(s_WantedRect.x + (int)(sec2px * t), s_WantedRect.y, 2, s_WantedRect.height), EditorGUIUtility.whiteTexture); if (r.width > 64) - EditorGUI.DropShadowLabel(new Rect(m_wantedRect.x, m_wantedRect.y, m_wantedRect.width, 20), string.Format("{0:00}:{1:00}.{2:000}", ts.Minutes, ts.Seconds, ts.Milliseconds)); + EditorGUI.DropShadowLabel(new Rect(s_WantedRect.x, s_WantedRect.y, s_WantedRect.width, 20), string.Format("{0:00}:{1:00}.{2:000}", ts.Minutes, ts.Seconds, ts.Milliseconds)); else - EditorGUI.DropShadowLabel(new Rect(m_wantedRect.x, m_wantedRect.y, m_wantedRect.width, 20), string.Format("{0:00}:{1:00}", ts.Minutes, ts.Seconds)); + EditorGUI.DropShadowLabel(new Rect(s_WantedRect.x, s_WantedRect.y, s_WantedRect.width, 20), string.Format("{0:00}:{1:00}", ts.Minutes, ts.Seconds)); } - PreviewGUI.EndScrollView(); } + + if (!m_MultiEditing && (s_PlayFirst || (s_AutoPlay && m_Clip != clip))) + { + // Autoplay preview + PlayClip(clip, 0, s_Loop); + s_PlayFirst = false; + } + // force update GUI if (playing) GUIView.current.Repaint(); diff --git a/Editor/Mono/Inspector/AudioManagerInspector.cs b/Editor/Mono/Inspector/AudioManagerInspector.cs index 814440c843..517d27e005 100644 --- a/Editor/Mono/Inspector/AudioManagerInspector.cs +++ b/Editor/Mono/Inspector/AudioManagerInspector.cs @@ -21,11 +21,11 @@ private class Styles public static GUIContent SampleRate = EditorGUIUtility.TrTextContent("System Sample Rate", "Sample rate at which the output device of the audio system runs. Individual sounds may run at different sample rates and will be slowed down/sped up accordingly to match the output rate."); public static GUIContent DSPBufferSize = EditorGUIUtility.TrTextContent("DSP Buffer Size", "Length of mixing buffer. This determines the output latency of the game."); public static GUIContent VirtualVoiceCount = EditorGUIUtility.TrTextContent("Max Virtual Voices", "Maximum number of sounds managed by the system. Even though at most RealVoiceCount of the loudest sounds will be physically playing, the remaining sounds will still be updating their play position."); - public static GUIContent RealVoiceCount = EditorGUIUtility.TrTextContent("Max Real Voices", "Maximum number of actual simultanously playing sounds."); + public static GUIContent RealVoiceCount = EditorGUIUtility.TrTextContent("Max Real Voices", "Maximum number of actual simultaneously playing sounds."); public static GUIContent SpatializerPlugin = EditorGUIUtility.TrTextContent("Spatializer Plugin", "Native audio plugin performing spatialized filtering of 3D sources."); public static GUIContent AmbisonicDecoderPlugin = EditorGUIUtility.TrTextContent("Ambisonic Decoder Plugin", "Native audio plugin performing ambisonic-to-binaural filtering of sources."); public static GUIContent DisableAudio = EditorGUIUtility.TrTextContent("Disable Unity Audio", "Prevent allocating the output device in the runtime. Use this if you want to use other sound systems than the built-in one."); - public static GUIContent VirtualizeEffects = EditorGUIUtility.TrTextContent("Virtualize Effects", "When enabled dynamically turn off effects and spatializers on AudioSources that are culled in order to save CPU."); + public static GUIContent VirtualizeEffects = EditorGUIUtility.TrTextContent("Virtualize Effects", "When enabled, dynamically turn off effects and spatializers on AudioSources that are culled in order to save CPU."); public static GUIContent DSPBufferSizeInfo = EditorGUIUtility.TrTextContent("The requested buffer size ({0}) has been overridden to {1} by the operating system"); } diff --git a/Editor/Mono/Inspector/AudioSourceInspector.cs b/Editor/Mono/Inspector/AudioSourceInspector.cs index 428a8ee663..d30de59e14 100644 --- a/Editor/Mono/Inspector/AudioSourceInspector.cs +++ b/Editor/Mono/Inspector/AudioSourceInspector.cs @@ -87,7 +87,7 @@ internal static class Styles public static GUIContent rolloffLabel = EditorGUIUtility.TrTextContent("Volume Rolloff", "Which type of rolloff curve to use"); public static string controlledByCurveLabel = "Controlled by curve"; public static GUIContent audioClipLabel = EditorGUIUtility.TrTextContent("AudioClip", "The AudioClip asset played by the AudioSource. Can be undefined if the AudioSource is generating a live stream of audio via OnAudioFilterRead."); - public static GUIContent panStereoLabel = EditorGUIUtility.TrTextContent("Stereo Pan", "Only valid for Mono and Stereo AudioClips. Mono sounds will be panned at constant power left and right. Stereo sounds will Stereo sounds have each left/right value faded up and down according to the specified pan value."); + public static GUIContent panStereoLabel = EditorGUIUtility.TrTextContent("Stereo Pan", "Only valid for Mono and Stereo AudioClips. Mono sounds will be panned at constant power left and right. Stereo sounds will have each left/right value faded up and down according to the specified pan value."); public static GUIContent spatialBlendLabel = EditorGUIUtility.TrTextContent("Spatial Blend", "Sets how much this AudioSource is treated as a 3D source. 3D sources are affected by spatial position and spread. If 3D Pan Level is 0, all spatial attenuation is ignored."); public static GUIContent reverbZoneMixLabel = EditorGUIUtility.TrTextContent("Reverb Zone Mix", "Sets how much of the signal this AudioSource is mixing into the global reverb associated with the zones. [0, 1] is a linear range (like volume) while [1, 1.1] lets you boost the reverb mix by 10 dB."); public static GUIContent dopplerLevelLabel = EditorGUIUtility.TrTextContent("Doppler Level", "Specifies how much the pitch is changed based on the relative velocity between AudioListener and AudioSource."); diff --git a/Editor/Mono/Inspector/Avatar/AvatarMappingEditor.cs b/Editor/Mono/Inspector/Avatar/AvatarMappingEditor.cs index 9cf9bfb61a..0a401c9782 100644 --- a/Editor/Mono/Inspector/Avatar/AvatarMappingEditor.cs +++ b/Editor/Mono/Inspector/Avatar/AvatarMappingEditor.cs @@ -58,8 +58,8 @@ internal class Styles public GUIContent enforceTPose = EditorGUIUtility.TrTextContent("Enforce T-Pose"); public GUIContent bipedPose = EditorGUIUtility.TrTextContent("Biped Pose"); - public GUIContent ShowError = EditorGUIUtility.TrTextContent("Show Error (s)..."); - public GUIContent CloseError = EditorGUIUtility.TrTextContent("Close Error (s)"); + public GUIContent ShowError = EditorGUIUtility.TrTextContent("Show Error(s)..."); + public GUIContent CloseError = EditorGUIUtility.TrTextContent("Close Error(s)"); public GUIContent dotFill = EditorGUIUtility.IconContent("AvatarInspector/DotFill"); public GUIContent dotFrame = EditorGUIUtility.IconContent("AvatarInspector/DotFrame"); diff --git a/Editor/Mono/Inspector/AvatarMaskInspector.cs b/Editor/Mono/Inspector/AvatarMaskInspector.cs index 833754b968..8e26aacf61 100644 --- a/Editor/Mono/Inspector/AvatarMaskInspector.cs +++ b/Editor/Mono/Inspector/AvatarMaskInspector.cs @@ -162,10 +162,10 @@ internal class AvatarMaskInspector : Editor private static class Styles { // Model Importer related options - public static GUIContent MaskDefinition = EditorGUIUtility.TrTextContent("Definition", "Choose between Create From This Model, Copy From Other Avatar. The first one create a Mask for this file and the second one use a Mask from another file to import animation."); + public static GUIContent MaskDefinition = EditorGUIUtility.TrTextContent("Definition", "Choose between Create From This Model, Copy From Other Avatar. The first one creates a Mask for this file and the second one uses a Mask from another file to import animation."); public static GUIContent[] MaskDefinitionOpt = { - EditorGUIUtility.TrTextContent("Create From This Model", "Create a Mask based on the model from this file. For Humanoid rig all the human transform are always imported and converted to muscle curve, thus they cannot be unchecked."), + EditorGUIUtility.TrTextContent("Create From This Model", "Create a Mask based on the model from this file. For Humanoid rig all the human transforms are always imported and converted to muscle curve, thus they cannot be unchecked."), EditorGUIUtility.TrTextContent("Copy From Other Mask", "Copy a Mask from another file to import animation clip."), EditorGUIUtility.TrTextContent("None ", " Import Everything") }; diff --git a/Editor/Mono/Inspector/AvatarPreview.cs b/Editor/Mono/Inspector/AvatarPreview.cs index 21ce1f6597..9dd3e3b381 100644 --- a/Editor/Mono/Inspector/AvatarPreview.cs +++ b/Editor/Mono/Inspector/AvatarPreview.cs @@ -26,16 +26,12 @@ private class ObjectSelectorOperation : ObjectSelectorReceiver { public static void Start(AvatarPreview owner) { - var operation = new ObjectSelectorOperation(owner, ObjectSelector.get); + var operation = ScriptableObject.CreateInstance(); + operation.m_Owner = owner; + operation.m_Selector = ObjectSelector.get; operation.Execute(); } - public ObjectSelectorOperation(AvatarPreview owner, ObjectSelector selector) - { - m_Owner = owner; - m_Selector = selector; - } - AvatarPreview m_Owner; ObjectSelector m_Selector; @@ -947,11 +943,12 @@ protected void HandleViewTool(Event evt, EventType eventType, int id, Rect previ } } - public void DoAvatarPreviewDrag(EventType type) + public void DoAvatarPreviewDrag(Event evt, EventType type) { if (type == EventType.DragUpdated) { DragAndDrop.visualMode = DragAndDropVisualMode.Link; + evt.Use(); } else if (type == EventType.DragPerform) { @@ -963,6 +960,8 @@ public void DoAvatarPreviewDrag(EventType type) DragAndDrop.AcceptDrag(); SetPreview(newPreviewObject); } + + evt.Use(); } } @@ -1066,7 +1065,7 @@ public void DoAvatarPreview(Rect rect, GUIStyle background) int previewSceneID = GUIUtility.GetControlID(m_PreviewSceneHint, FocusType.Passive); type = evt.GetTypeForControl(previewSceneID); - DoAvatarPreviewDrag(type); + DoAvatarPreviewDrag(evt, type); HandleViewTool(evt, type, previewSceneID, previewRect); DoAvatarPreviewFrame(evt, type, previewRect); diff --git a/Editor/Mono/Inspector/BoxColliderEditor.cs b/Editor/Mono/Inspector/BoxColliderEditor.cs index f799393a69..8abf235907 100644 --- a/Editor/Mono/Inspector/BoxColliderEditor.cs +++ b/Editor/Mono/Inspector/BoxColliderEditor.cs @@ -15,7 +15,7 @@ internal class BoxColliderEditor : PrimitiveCollider3DEditor SerializedProperty m_Size; private readonly BoxBoundsHandle m_BoundsHandle = new BoxBoundsHandle(); - protected GUIContent centerContent = EditorGUIUtility.TrTextContent("Center", "The position of the Collider in the object’s local space."); + protected GUIContent centerContent = EditorGUIUtility.TrTextContent("Center", "The position of the Collider in the object's local space."); protected GUIContent sizeContent = EditorGUIUtility.TrTextContent("Size", "The size of the Collider in the X, Y, Z directions."); diff --git a/Editor/Mono/Inspector/CameraEditor.cs b/Editor/Mono/Inspector/CameraEditor.cs index 1a1ca5eec8..dd8e4bf066 100644 --- a/Editor/Mono/Inspector/CameraEditor.cs +++ b/Editor/Mono/Inspector/CameraEditor.cs @@ -29,17 +29,17 @@ private static class Styles public static GUIContent background = EditorGUIUtility.TrTextContent("Background", "The Camera clears the screen to this color before rendering."); public static GUIContent projection = EditorGUIUtility.TrTextContent("Projection", "How the Camera renders perspective.\n\nChoose Perspective to render objects with perspective.\n\nChoose Orthographic to render objects uniformly, with no sense of perspective."); public static GUIContent size = EditorGUIUtility.TrTextContent("Size", "The vertical size of the camera view."); - public static GUIContent fieldOfView = EditorGUIUtility.TrTextContent("Field of View", "The camera’s view angle measured in degrees along the selected axis."); - public static GUIContent viewportRect = EditorGUIUtility.TrTextContent("Viewport Rect", "Four values that indicate where on the screen this camera view will be drawn. Measured in Viewport Coordinates (values 0–1)."); + public static GUIContent fieldOfView = EditorGUIUtility.TrTextContent("Field of View", "The camera's view angle measured in degrees along the selected axis."); + public static GUIContent viewportRect = EditorGUIUtility.TrTextContent("Viewport Rect", "Four values that indicate where on the screen this camera view will be drawn. Measured in Viewport Coordinates (values 0-1)."); public static GUIContent sensorSize = EditorGUIUtility.TrTextContent("Sensor Size", "The size of the camera sensor in millimeters."); public static GUIContent lensShift = EditorGUIUtility.TrTextContent("Lens Shift", "Offset from the camera sensor. Use these properties to simulate a shift lens. Measured as a multiple of the sensor size."); public static GUIContent physicalCamera = EditorGUIUtility.TrTextContent("Physical Camera", "Enables Physical camera mode. When checked, the field of view is calculated from properties for simulating physical attributes (focal length, sensor size, and lens shift)"); public static GUIContent cameraType = EditorGUIUtility.TrTextContent("Sensor Type", "Common sensor sizes. Choose an item to set Sensor Size, or edit Sensor Size for your custom settings."); - public static GUIContent renderingPath = EditorGUIUtility.TrTextContent("Rendering Path", "Choose a rendering method for this camera.\n\nUse Graphics Settings to use the rendering path specified in Player settings.\n\nUse Forward to render all objects with one pass per material.\n\nUse Deferred to draw all objects once without lighting and then draw the lighting of all objects at the end of the render queue.\n\nUse Legacy Vertex Lit to to render all lights in a single pass, calculated in vertices.\n\nLegacy Deferred has been deprecated."); + public static GUIContent renderingPath = EditorGUIUtility.TrTextContent("Rendering Path", "Choose a rendering method for this camera.\n\nUse Graphics Settings to use the rendering path specified in Player settings.\n\nUse Forward to render all objects with one pass per material.\n\nUse Deferred to draw all objects once without lighting and then draw the lighting of all objects at the end of the render queue.\n\nUse Legacy Vertex Lit to render all lights in a single pass, calculated in vertices.\n\nLegacy Deferred has been deprecated."); public static GUIContent focalLength = EditorGUIUtility.TrTextContent("Focal Length", "The simulated distance between the lens and the sensor of the physical camera. Larger values give a narrower field of view."); public static GUIContent allowOcclusionCulling = EditorGUIUtility.TrTextContent("Occlusion Culling", "Occlusion Culling means that objects that are hidden behind other objects are not rendered, for example if they are behind walls."); public static GUIContent allowHDR = EditorGUIUtility.TrTextContent("HDR", "High Dynamic Range gives you a wider range of light intensities, so your lighting looks more realistic. With it, you can still see details and experience less saturation even with bright light."); - public static GUIContent allowMSAA = EditorGUIUtility.TrTextContent("MSAA", "Use Multi Sample Anti-Aliasing to reduce aliasing."); + public static GUIContent allowMSAA = EditorGUIUtility.TrTextContent("MSAA", "Use Multi Sample Anti-aliasing to reduce aliasing."); public static GUIContent gateFit = EditorGUIUtility.TrTextContent("Gate Fit", "Determines how the rendered area (resolution gate) fits into the sensor area (film gate)."); public static GUIContent allowDynamicResolution = EditorGUIUtility.TrTextContent("Allow Dynamic Resolution", "Scales render textures to support dynamic resolution if the target platform/graphics API supports it."); public static GUIContent FOVAxisMode = EditorGUIUtility.TrTextContent("FOV Axis", "Field of view axis."); diff --git a/Editor/Mono/Inspector/ClothInspector.cs b/Editor/Mono/Inspector/ClothInspector.cs index e4501bd033..a874ace64b 100644 --- a/Editor/Mono/Inspector/ClothInspector.cs +++ b/Editor/Mono/Inspector/ClothInspector.cs @@ -88,6 +88,7 @@ public enum CollisionVisualizationMode { SelfCollision, InterCollision }; int m_NumSelection = 0; + [NonSerialized] SkinnedMeshRenderer m_SkinnedMeshRenderer; const HideFlags kMeshColliderHideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector | HideFlags.DontSaveInEditor | HideFlags.NotEditable; const HideFlags kRequiredHideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector; @@ -102,6 +103,7 @@ private static class Styles public static readonly GUIContent paintCollisionParticles = EditorGUIUtility.TrTextContent("Paint Collision Particles"); public static readonly GUIContent selectCollisionParticles = EditorGUIUtility.TrTextContent("Select Collision Particles"); public static readonly GUIContent brushRadiusString = EditorGUIUtility.TrTextContent("Brush Radius"); + public static readonly GUIContent constraintSizeString = EditorGUIUtility.TrTextContent("Constraint Size"); public static readonly GUIContent selfAndInterCollisionMode = EditorGUIUtility.TrTextContent("Paint or Select Particles"); public static readonly GUIContent backFaceManipulationMode = EditorGUIUtility.TrTextContent("Back Face Manipulation"); public static readonly GUIContent manipulateBackFaceString = EditorGUIUtility.TrTextContent("Manipulate Backfaces"); @@ -840,6 +842,8 @@ void SelectionGUI() } cloth.coefficients = coefficients; } + + EditConstraintSize(); } void CollSelectionGUI() @@ -919,6 +923,19 @@ void EditBrushSize() } } + void EditConstraintSize() + { + EditorGUI.BeginChangeCheck(); + float fieldValue = EditorGUILayout.FloatField(Styles.constraintSizeString, state.ConstraintSize); + bool changed = EditorGUI.EndChangeCheck(); + if (changed) + { + state.ConstraintSize = fieldValue; + if (state.ConstraintSize < 0.0f) + state.ConstraintSize = 0.0f; + } + } + void PaintGUI() { state.PaintMaxDistance = PaintField(state.PaintMaxDistance, ref state.PaintMaxDistanceEnabled, DrawMode.MaxDistance); @@ -940,6 +957,7 @@ void PaintGUI() } EditBrushSize(); + EditConstraintSize(); } int GetMouseVertex(Event e) diff --git a/Editor/Mono/Inspector/Collider2DEditorBase.cs b/Editor/Mono/Inspector/Collider2DEditorBase.cs index afe94e682a..3ffd2c3f36 100644 --- a/Editor/Mono/Inspector/Collider2DEditorBase.cs +++ b/Editor/Mono/Inspector/Collider2DEditorBase.cs @@ -16,7 +16,7 @@ internal abstract class Collider2DEditorBase : ColliderEditorBase protected class Styles { public static readonly GUIContent s_ColliderEditDisableHelp = EditorGUIUtility.TrTextContent("Collider cannot be edited because it is driven by SpriteRenderer's tiling properties."); - public static readonly GUIContent s_AutoTilingLabel = EditorGUIUtility.TrTextContent("Auto Tiling ", " When enabled, the collider's shape will update automaticaly based on the SpriteRenderer's tiling properties"); + public static readonly GUIContent s_AutoTilingLabel = EditorGUIUtility.TrTextContent("Auto Tiling ", " When enabled, the collider's shape will update automatically based on the SpriteRenderer's tiling properties"); } private SerializedProperty m_Density; diff --git a/Editor/Mono/Inspector/CompositeCollider2DEditor.cs b/Editor/Mono/Inspector/CompositeCollider2DEditor.cs index 2b5cb66a1c..9e9cf73bda 100644 --- a/Editor/Mono/Inspector/CompositeCollider2DEditor.cs +++ b/Editor/Mono/Inspector/CompositeCollider2DEditor.cs @@ -17,6 +17,7 @@ internal class CompositeCollider2DEditor : Collider2DEditorBase private SerializedProperty m_GenerationType; private SerializedProperty m_VertexDistance; private SerializedProperty m_EdgeRadius; + private SerializedProperty m_OffsetDistance; readonly AnimBool m_ShowEdgeRadius = new AnimBool(); readonly AnimBool m_ShowManualGenerationButton = new AnimBool(); @@ -28,6 +29,7 @@ public override void OnEnable() m_GenerationType = serializedObject.FindProperty("m_GenerationType"); m_VertexDistance = serializedObject.FindProperty("m_VertexDistance"); m_EdgeRadius = serializedObject.FindProperty("m_EdgeRadius"); + m_OffsetDistance = serializedObject.FindProperty("m_OffsetDistance"); m_ShowEdgeRadius.value = targets.Where(x => (x as CompositeCollider2D).geometryType == CompositeCollider2D.GeometryType.Polygons).Count() == 0; m_ShowEdgeRadius.valueChanged.AddListener(Repaint); m_ShowManualGenerationButton.value = targets.Where(x => (x as CompositeCollider2D).generationType != CompositeCollider2D.GenerationType.Manual).Count() == 0; @@ -49,6 +51,7 @@ public override void OnInspectorGUI() EditorGUILayout.PropertyField(m_GeometryType); EditorGUILayout.PropertyField(m_GenerationType); EditorGUILayout.PropertyField(m_VertexDistance); + EditorGUILayout.PropertyField(m_OffsetDistance); m_ShowManualGenerationButton.target = targets.Where(x => (x as CompositeCollider2D).generationType != CompositeCollider2D.GenerationType.Manual).Count() == 0; if (EditorGUILayout.BeginFadeGroup(m_ShowManualGenerationButton.faded)) diff --git a/Editor/Mono/Inspector/CubemapInspector.cs b/Editor/Mono/Inspector/CubemapInspector.cs index 0749b6d37f..5c9236f8df 100644 --- a/Editor/Mono/Inspector/CubemapInspector.cs +++ b/Editor/Mono/Inspector/CubemapInspector.cs @@ -109,7 +109,7 @@ public override void OnInspectorGUI() bool streamingMipmaps = TextureUtil.GetCubemapStreamingMipmaps(c); if (useMipMap) { - streamingMipmaps = EditorGUILayout.Toggle(EditorGUIUtility.TrTextContent("Streaming Mip Maps", "Don't load image data immediately, but wait till image data is requested from script."), streamingMipmaps); + streamingMipmaps = EditorGUILayout.Toggle(EditorGUIUtility.TrTextContent("Streaming Mipmaps", "Don't load image data immediately but wait till image data is requested from script."), streamingMipmaps); } bool linear = TextureUtil.GetLinearSampled(c); diff --git a/Editor/Mono/Inspector/DirectorEditor.cs b/Editor/Mono/Inspector/DirectorEditor.cs index 075cf48795..97df63b169 100644 --- a/Editor/Mono/Inspector/DirectorEditor.cs +++ b/Editor/Mono/Inspector/DirectorEditor.cs @@ -243,12 +243,15 @@ private static bool PropertyFieldAsObject(SerializedProperty property, GUIConten int id = GUIUtility.GetControlID(Styles.ObjectFieldControlID, FocusType.Keyboard, rect); rect = EditorGUI.PrefixLabel(rect, id, label); var result = EditorGUI.DoObjectField(rect, rect, id, property.objectReferenceValue, objType, null, null, allowSceneObjects, EditorStyles.objectField); + + bool retValue = false; if (EditorGUI.EndChangeCheck()) { property.objectReferenceValue = result; - return true; + retValue = true; } - return false; + EditorGUI.EndProperty(); + return retValue; } // Does not use Properties because time is not a serialized property diff --git a/Editor/Mono/Inspector/Editor.cs b/Editor/Mono/Inspector/Editor.cs index 25d7716ecc..fd4687658c 100644 --- a/Editor/Mono/Inspector/Editor.cs +++ b/Editor/Mono/Inspector/Editor.cs @@ -325,6 +325,7 @@ public partial class Editor : ScriptableObject, IPreviewable, IToolModeOwner int m_ReferenceTargetIndex = 0; PropertyHandlerCache m_PropertyHandlerCache = new PropertyHandlerCache(); IPreviewable m_DummyPreview; + AudioFilterGUI m_AudioFilterGUI; internal SerializedObject m_SerializedObject = null; internal SerializedProperty m_EnabledProperty = null; @@ -553,13 +554,32 @@ private void OnDisableINTERNAL() internal virtual SerializedObject GetSerializedObjectInternal() { if (m_SerializedObject == null) + { + CreateSerializedObject(); + } + + return m_SerializedObject; + } + + internal class SerializedObjectNotCreatableException : Exception + { + public SerializedObjectNotCreatableException(string msg) : base(msg) {} + } + + private void CreateSerializedObject() + { + try { m_SerializedObject = new SerializedObject(targets, m_Context); m_SerializedObject.inspectorMode = inspectorMode; m_EnabledProperty = m_SerializedObject.FindProperty("m_Enabled"); } - - return m_SerializedObject; + catch (ArgumentException e) + { + m_SerializedObject = null; + m_EnabledProperty = null; + throw new SerializedObjectNotCreatableException(e.Message); + } } internal virtual void InternalSetTargets(UnityObject[] t) { m_Targets = t; } @@ -668,7 +688,17 @@ internal static bool DoDrawDefaultInspector(SerializedObject obj) internal bool DoDrawDefaultInspector() { - return DoDrawDefaultInspector(serializedObject); + bool res = DoDrawDefaultInspector(serializedObject); + + var behaviour = target as MonoBehaviour; + if (behaviour == null || !AudioUtil.HasAudioCallback(behaviour) || AudioUtil.GetCustomFilterChannelCount(behaviour) <= 0) + return res; + + // If we have an OnAudioFilterRead callback, draw vu meter + if (m_AudioFilterGUI == null) + m_AudioFilterGUI = new AudioFilterGUI(); + m_AudioFilterGUI.DrawAudioFilterGUI(behaviour); + return res; } // Repaint any inspectors that shows this editor. @@ -934,7 +964,7 @@ internal void DrawPostIconContent() public static void DrawFoldoutInspector(UnityObject target, ref Editor editor) { - if (editor != null && editor.target != target) + if (editor != null && (editor.target != target || target == null)) { UnityObject.DestroyImmediate(editor); editor = null; @@ -1014,14 +1044,21 @@ public virtual void ReloadPreviewInstances() preview.ReloadPreviewInstances(); } + // Some custom editors manually display SerializedObjects with only private properties + // Setting this to true allows them to properly toggling the visibility via the standard header foldout + internal bool alwaysAllowExpansion {get; set;} + // Auxiliary method that determines whether this editor has a set of public properties and, as thus, // can be expanded via a foldout. This is used in order to determine whether a foldout needs to be // rendered on top of the inspector title bar or not. Some examples of editors that don't require // a foldout are GUI Layer and Audio Listener. internal bool CanBeExpandedViaAFoldout() { + if (alwaysAllowExpansion) + return true; + if (m_SerializedObject == null) - m_SerializedObject = new SerializedObject(targets, m_Context); + CreateSerializedObject(); else m_SerializedObject.Update(); m_SerializedObject.inspectorMode = inspectorMode; diff --git a/Editor/Mono/Inspector/EditorElement.cs b/Editor/Mono/Inspector/EditorElement.cs index 6b4aabd2a7..ceb912fe44 100644 --- a/Editor/Mono/Inspector/EditorElement.cs +++ b/Editor/Mono/Inspector/EditorElement.cs @@ -51,6 +51,18 @@ private bool IsEditorValid() internal InspectorElement m_InspectorElement { get; private set; } IMGUIContainer m_Footer; + static class Styles + { + public static GUIStyle importedObjectsHeaderStyle = new GUIStyle("IN BigTitle"); + + static Styles() + { + importedObjectsHeaderStyle.font = EditorStyles.label.font; + importedObjectsHeaderStyle.fontSize = EditorStyles.label.fontSize; + importedObjectsHeaderStyle.alignment = TextAnchor.UpperLeft; + } + } + internal EditorElement(int editorIndex, InspectorWindow iw) { m_EditorIndex = editorIndex; @@ -121,13 +133,15 @@ internal void Reinit(int editorIndex) private void UpdateInspectorVisibility() { - if (!editor.CanBeExpandedViaAFoldout()) + if (editor.CanBeExpandedViaAFoldout()) { - SetElementVisible(m_InspectorElement, false); + m_Footer.style.marginTop = 0.0f; + m_InspectorElement.style.paddingBottom = InspectorWindow.kEditorElementPaddingBottom; } else { - SetElementVisible(m_InspectorElement, true); + m_Footer.style.marginTop = -kFooterDefaultHeight; + m_InspectorElement.style.paddingBottom = 0.0f; } } @@ -156,6 +170,18 @@ IMGUIContainer BuildHeaderElement(string editorTitle) return headerElement; } + private static UQueryState ImguiContainersQuery = new UQueryBuilder(null).SingleBaseType().Build(); + + + internal static void InvalidateIMGUILayouts(VisualElement element) + { + if (element != null) + { + var q = ImguiContainersQuery.RebuildOn(element); + q.ForEach(e => e.MarkDirtyLayout()); + } + } + void HeaderOnGUI() { if (!IsEditorValid()) @@ -192,13 +218,20 @@ void HeaderOnGUI() m_DragRect = DrawEditorHeader(target, ref wasVisible); } - wasVisible = wasVisible && editor.CanBeExpandedViaAFoldout(); + if (GUI.changed) + { + // If the header changed something, we must trigger a layout calculating on imgui children + // Fixes Material editor toggling layout issues (case 1148706) + InvalidateIMGUILayouts(this); + } if (wasVisible != IsElementVisible(m_InspectorElement)) { SetElementVisible(m_InspectorElement, wasVisible); } + UpdateInspectorVisibility(); + var multiEditingSupported = inspectorWindow.IsMultiEditingSupported(editor, target); if (!multiEditingSupported && wasVisible) @@ -267,11 +300,15 @@ bool DrawEditorLargeHeader(ref bool wasVisible) var importedObjectBarRect = GUILayoutUtility.GetRect(16, 16); importedObjectBarRect.height = 17; - // Clip the label to avoid a black border at the bottom - GUI.BeginGroup(importedObjectBarRect); - GUI.Label(new Rect(0, 0, importedObjectBarRect.width, importedObjectBarRect.height), - "Imported Object", "OL Title"); - GUI.EndGroup(); + var headerText = "Imported Object"; + if (m_Editors.Length > 1) + { + if (m_Editors[0] is PrefabImporterEditor && m_Editors[1] is GameObjectInspector) + headerText = "Root in Prefab Asset"; + } + + GUILayout.Label(headerText, Styles.importedObjectsHeaderStyle, GUILayout.ExpandWidth(true)); + GUILayout.Space(-7f); // Ensures no spacing between this header and the next header } // Header diff --git a/Editor/Mono/Inspector/EditorSettingsInspector.cs b/Editor/Mono/Inspector/EditorSettingsInspector.cs index 4c9291dca7..baf744f3c8 100644 --- a/Editor/Mono/Inspector/EditorSettingsInspector.cs +++ b/Editor/Mono/Inspector/EditorSettingsInspector.cs @@ -33,11 +33,12 @@ class Content public static GUIContent workOffline = EditorGUIUtility.TrTextContent("Work Offline"); public static GUIContent allowAsyncUpdate = EditorGUIUtility.TrTextContent("Allow Async Update"); public static GUIContent showFailedCheckouts = EditorGUIUtility.TrTextContent("Show Failed Checkouts"); + public static GUIContent overwriteFailedCheckoutAssets = EditorGUIUtility.TrTextContent("Overwrite Failed Checkout Assets", "When on, assets that can not be checked out will get saved anyway."); public static GUIContent assetPipeline = EditorGUIUtility.TrTextContent("Asset Pipeline (experimental)"); public static GUIContent cacheServer = EditorGUIUtility.TrTextContent("Cache Server"); public static GUIContent assetSerialization = EditorGUIUtility.TrTextContent("Asset Serialization"); - public static GUIContent defaultBehaviorMode = EditorGUIUtility.TrTextContent("Default Behavior Mode"); + public static GUIContent defaultBehaviorMode = EditorGUIUtility.TrTextContent("Default Behaviour Mode"); public static GUIContent graphics = EditorGUIUtility.TrTextContent("Graphics"); public static GUIContent showLightmapResolutionOverlay = EditorGUIUtility.TrTextContent("Show Lightmap Resolution Overlay"); @@ -49,7 +50,7 @@ class Content public static GUIContent rootNamespace = EditorGUIUtility.TrTextContent("Root namespace"); public static GUIContent etcTextureCompressor = EditorGUIUtility.TrTextContent("ETC Texture Compressor"); - public static GUIContent behavior = EditorGUIUtility.TrTextContent("Behavior"); + public static GUIContent behavior = EditorGUIUtility.TrTextContent("Behaviour"); public static GUIContent fast = EditorGUIUtility.TrTextContent("Fast"); public static GUIContent normal = EditorGUIUtility.TrTextContent("Normal"); public static GUIContent best = EditorGUIUtility.TrTextContent("Best"); @@ -261,26 +262,6 @@ public void OnEnable() LoadEditorUserSettings(); - - m_AssetPipelineMode = m_EditorUserSettings.FindProperty("m_AssetPipelineMode"); - m_CacheServerMode = m_EditorUserSettings.FindProperty("m_CacheServerMode"); - m_CacheServers = m_EditorUserSettings.FindProperty("m_CacheServers"); - - - m_CacheServerConnectionState = CacheServerConnectionState.Unknown; - s_ForcedAssetPipelineWarning = null; - - if (m_CacheServerList == null) - { - m_CacheServerList = new ReorderableList(serializedObject, m_CacheServers, true, false, true, true); - m_CacheServerList.onReorderCallback = (ReorderableList list) => { serializedObject.ApplyModifiedProperties(); }; - m_CacheServerList.onAddCallback = (ReorderableList list) => { m_CacheServers.arraySize += 1; serializedObject.ApplyModifiedProperties(); }; - m_CacheServerList.onRemoveCallback = (ReorderableList list) => { ReorderableList.defaultBehaviours.DoRemoveButton(list); serializedObject.ApplyModifiedProperties(); }; - m_CacheServerList.onCanRemoveCallback = (ReorderableList list) => { return list.index < m_CacheServers.arraySize && list.index >= 0; }; - m_CacheServerList.drawElementCallback = DrawCacheServerListElement; - m_CacheServerList.elementHeight = EditorGUIUtility.singleLineHeight + 2; - m_CacheServerList.headerHeight = 3; - } } public void OnDisable() @@ -345,6 +326,11 @@ void BuildRemoteDeviceList() public override void OnInspectorGUI() { + if (m_EditorUserSettings != null && !m_EditorUserSettings.targetObject) + { + LoadEditorUserSettings(); + } + serializedObject.Update(); // GUI.enabled hack because we don't want some controls to be disabled if the EditorSettings.asset is locked @@ -472,7 +458,10 @@ public override void OnInspectorGUI() } if (Provider.hasCheckoutSupport) + { EditorUserSettings.showFailedCheckout = EditorGUILayout.Toggle(Content.showFailedCheckouts, EditorUserSettings.showFailedCheckout); + EditorUserSettings.overwriteFailedCheckoutAssets = EditorGUILayout.Toggle(Content.overwriteFailedCheckoutAssets, EditorUserSettings.overwriteFailedCheckoutAssets); + } GUI.enabled = editorEnabled; @@ -588,6 +577,25 @@ private void LoadEditorUserSettings() m_EditorUserSettings = new SerializedObject(o); } } + + m_AssetPipelineMode = m_EditorUserSettings.FindProperty("m_AssetPipelineMode"); + m_CacheServerMode = m_EditorUserSettings.FindProperty("m_CacheServerMode"); + m_CacheServers = m_EditorUserSettings.FindProperty("m_CacheServers"); + + m_CacheServerConnectionState = CacheServerConnectionState.Unknown; + s_ForcedAssetPipelineWarning = null; + + if (m_CacheServerList == null) + { + m_CacheServerList = new ReorderableList(serializedObject, m_CacheServers, true, false, true, true); + m_CacheServerList.onReorderCallback = (ReorderableList list) => { serializedObject.ApplyModifiedProperties(); }; + m_CacheServerList.onAddCallback = (ReorderableList list) => { m_CacheServers.arraySize += 1; serializedObject.ApplyModifiedProperties(); }; + m_CacheServerList.onRemoveCallback = (ReorderableList list) => { ReorderableList.defaultBehaviours.DoRemoveButton(list); serializedObject.ApplyModifiedProperties(); }; + m_CacheServerList.onCanRemoveCallback = (ReorderableList list) => { return list.index < m_CacheServers.arraySize && list.index >= 0; }; + m_CacheServerList.drawElementCallback = DrawCacheServerListElement; + m_CacheServerList.elementHeight = EditorGUIUtility.singleLineHeight + 2; + m_CacheServerList.headerHeight = 3; + } } private void DoProjectGenerationSettings() diff --git a/Editor/Mono/Inspector/Enlighten/LightmapParameters.cs b/Editor/Mono/Inspector/Enlighten/LightmapParameters.cs index 4e6c121399..28b256d8a2 100644 --- a/Editor/Mono/Inspector/Enlighten/LightmapParameters.cs +++ b/Editor/Mono/Inspector/Enlighten/LightmapParameters.cs @@ -118,7 +118,7 @@ internal override void OnHeaderControlsGUI() private class Styles { public static readonly GUIContent generalGIContent = EditorGUIUtility.TrTextContent("General GI", "Settings used in both Precomputed Realtime Global Illumination and Baked Global Illumination."); - public static readonly GUIContent precomputedRealtimeGIContent = EditorGUIUtility.TrTextContent("Realtime GI", "Settings used in Precomputed Realtime Global Illumination where it is precomputed how indirect light can bounce between static objects, but the final lighting is done at runtime. Lights, ambient lighting in addition to the materials and emission of static objects can still be changed at runtime. Only static objects can affect GI by blocking and bouncing light, but non-static objects can receive bounced light via light probes."); // Reuse the label from the Lighting window + public static readonly GUIContent precomputedRealtimeGIContent = EditorGUIUtility.TrTextContent("Realtime GI (Deprecated)", "Settings used in Precomputed Realtime Global Illumination where it is precomputed how indirect light can bounce between static objects, but the final lighting is done at runtime. Lights, ambient lighting in addition to the materials and emission of static objects can still be changed at runtime. Only static objects can affect GI by blocking and bouncing light, but non-static objects can receive bounced light via light probes."); // Reuse the label from the Lighting window public static readonly GUIContent resolutionContent = EditorGUIUtility.TrTextContent("Resolution", "Realtime lightmap resolution in texels per world unit. This value is multiplied by the realtime resolution in the Lighting window to give the output lightmap resolution. This should generally be an order of magnitude less than what is common for baked lightmaps to keep the precompute time manageable and the performance at runtime acceptable. Note that if this is made more fine-grained, then the Irradiance Budget will often need to be increased too, to fully take advantage of this increased detail."); public static readonly GUIContent clusterResolutionContent = EditorGUIUtility.TrTextContent("Cluster Resolution", "The ratio between the resolution of the clusters with which light bounce is calculated and the resolution of the output lightmaps that sample from these."); public static readonly GUIContent irradianceBudgetContent = EditorGUIUtility.TrTextContent("Irradiance Budget", "The amount of data used by each texel in the output lightmap. Specifies how fine-grained a view of the scene an output texel has. Small values mean more averaged out lighting, since the light contributions from more clusters are treated as one. Affects runtime memory usage and to a lesser degree runtime CPU usage."); diff --git a/Editor/Mono/Inspector/GameObjectInspector.cs b/Editor/Mono/Inspector/GameObjectInspector.cs index 63981c5b21..c706ec8245 100644 --- a/Editor/Mono/Inspector/GameObjectInspector.cs +++ b/Editor/Mono/Inspector/GameObjectInspector.cs @@ -126,6 +126,7 @@ public void Dispose() bool m_IsMissing; bool m_IsPrefabInstanceAnyRoot; bool m_IsPrefabInstanceOutermostRoot; + bool m_IsAssetRoot; bool m_AllOfSamePrefabType = true; public void OnEnable() @@ -158,6 +159,7 @@ void CalculatePrefabStatus() m_IsPrefabInstanceAnyRoot = true; m_IsPrefabInstanceOutermostRoot = true; m_AllOfSamePrefabType = true; + m_IsAssetRoot = false; PrefabAssetType firstType = PrefabUtility.GetPrefabAssetType(targets[0]); PrefabInstanceStatus firstStatus = PrefabUtility.GetPrefabInstanceStatus(targets[0]); @@ -174,8 +176,14 @@ void CalculatePrefabStatus() m_IsPrefabInstanceAnyRoot = false; // Conservative is false if any is false if (!m_IsPrefabInstanceAnyRoot || !PrefabUtility.IsOutermostPrefabInstanceRoot(go)) m_IsPrefabInstanceOutermostRoot = false; // Conservative is false if any is false + if (PrefabUtility.IsPartOfPrefabAsset(go)) + { m_IsAsset = true; // Conservative is true if any is true + if (go.transform.parent == null) + m_IsAssetRoot = true; + } + if (m_IsAsset && PrefabUtility.IsPartOfImmutablePrefab(go)) m_ImmutableSelf = true; // Conservative is true if any is true GameObject originalSourceOrVariant = PrefabUtility.GetOriginalSourceOrVariantRoot(go); @@ -275,8 +283,12 @@ internal bool DrawInspector() } EditorGUILayout.EndHorizontal(); - // Name - EditorGUILayout.DelayedTextField(m_Name, GUIContent.none); + // Disable the name field of root GO in prefab asset + using (new EditorGUI.DisabledScope(m_IsAsset && m_IsAssetRoot)) + { + // Name + EditorGUILayout.DelayedTextField(m_Name, GUIContent.none); + } // Static flags toggle DoStaticToggleField(go); @@ -313,7 +325,7 @@ internal bool DrawInspector() private void DoPrefabButtons() { - if (!m_IsPrefabInstanceAnyRoot) + if (!m_IsPrefabInstanceAnyRoot || m_IsAsset) return; using (new EditorGUI.DisabledScope(m_PlayModeObjects)) @@ -851,7 +863,9 @@ public override void OnPreviewGUI(Rect r, GUIStyle background) DoRenderPreview(); previewUtility.EndAndDrawPreview(r); var copy = new RenderTexture(previewUtility.renderTexture); - Graphics.CopyTexture(previewUtility.renderTexture, copy); + var previous = RenderTexture.active; + Graphics.Blit(previewUtility.renderTexture, copy); + RenderTexture.active = previous; m_PreviewCache.Add(referenceTargetIndex, copy); } } @@ -875,9 +889,19 @@ public void OnSceneDrag(SceneView sceneView) Scene destinationScene = sceneView.customScene.IsValid() ? sceneView.customScene : SceneManager.GetActiveScene(); if (dragObject == null) { - dragObject = (GameObject)PrefabUtility.InstantiatePrefab(prefabAssetRoot, destinationScene); + if (!EditorApplication.isPlaying || EditorSceneManager.IsPreviewScene(destinationScene)) + { + dragObject = (GameObject)PrefabUtility.InstantiatePrefab(prefabAssetRoot, destinationScene); + dragObject.name = go.name; + } + else + { + // Instatiate as regular GameObject in Play Mode so runtime logic + // won't run into restrictions on restructuring Prefab instances. + dragObject = Instantiate(prefabAssetRoot); + SceneManager.MoveGameObjectToScene(dragObject, destinationScene); + } dragObject.hideFlags = HideFlags.HideInHierarchy; - dragObject.name = go.name; } if (HandleUtility.ignoreRaySnapObjects == null) @@ -937,7 +961,8 @@ public void OnSceneDrag(SceneView sceneView) HandleUtility.ignoreRaySnapObjects = null; if (SceneView.mouseOverWindow != null) SceneView.mouseOverWindow.Focus(); - dragObject.name = uniqueName; + if (!Application.IsPlaying(dragObject)) + dragObject.name = uniqueName; dragObject = null; evt.Use(); break; diff --git a/Editor/Mono/Inspector/GenericInspector.cs b/Editor/Mono/Inspector/GenericInspector.cs index 40c4842b97..bbc763d37b 100644 --- a/Editor/Mono/Inspector/GenericInspector.cs +++ b/Editor/Mono/Inspector/GenericInspector.cs @@ -15,7 +15,6 @@ private enum OptimizedBlockState NoOptimizedBlock } - private AudioFilterGUI m_AudioFilterGUI; private float m_LastHeight; private Rect m_LastVisibleRect; private OptimizedBlockState m_OptimizedBlockState = OptimizedBlockState.CheckOptimizedBlock; @@ -78,6 +77,8 @@ internal override bool GetOptimizedGUIBlock(bool isDirty, bool isVisible, out fl internal override bool OnOptimizedInspectorGUI(Rect contentRect) { + m_SerializedObject.UpdateIfRequiredOrScript(); + bool childrenAreExpanded = true; bool wasEnabled = GUI.enabled; var visibleRect = GUIClip.visibleRect; @@ -202,18 +203,6 @@ public override void OnInspectorGUI() return; base.OnInspectorGUI(); - - var behaviour = target as MonoBehaviour; - if (behaviour != null) - { - // Does this have a AudioRead callback? - if (AudioUtil.HasAudioCallback(behaviour) && AudioUtil.GetCustomFilterChannelCount(behaviour) > 0) - { - if (m_AudioFilterGUI == null) - m_AudioFilterGUI = new AudioFilterGUI(); - m_AudioFilterGUI.DrawAudioFilterGUI(behaviour); - } - } } } } diff --git a/Editor/Mono/Inspector/GraphicsSettingsInspector.cs b/Editor/Mono/Inspector/GraphicsSettingsInspector.cs index 6f5940483c..829e3d26ba 100644 --- a/Editor/Mono/Inspector/GraphicsSettingsInspector.cs +++ b/Editor/Mono/Inspector/GraphicsSettingsInspector.cs @@ -26,7 +26,8 @@ internal class Styles public static readonly GUIContent tierSettings = EditorGUIUtility.TrTextContent("Tier Settings"); public static readonly GUIContent builtinSettings = EditorGUIUtility.TrTextContent("Built-in Shader Settings"); public static readonly GUIContent shaderStrippingSettings = EditorGUIUtility.TrTextContent("Shader Stripping"); - public static readonly GUIContent shaderPreloadSettings = EditorGUIUtility.TrTextContent("Shader Preloading"); + public static readonly GUIContent shaderPreloadSettings = EditorGUIUtility.TrTextContent("Shader Loading"); + public static readonly GUIContent logWhenShaderIsCompiled = EditorGUIUtility.TrTextContent("Log Shader Compilation", "When enabled, the player will print shader information each time a shader is being compiled (development and debug mode only)."); public static readonly GUIContent cameraSettings = EditorGUIUtility.TrTextContent("Camera Settings"); public static readonly GUIContent renderPipeSettings = EditorGUIUtility.TrTextContent("Scriptable Render Pipeline Settings"); public static readonly GUIContent renderPipeLabel = EditorGUIUtility.TrTextContent("Scriptable Render Pipeline"); @@ -40,6 +41,7 @@ internal class Styles SerializedProperty m_TransparencySortMode; SerializedProperty m_TransparencySortAxis; SerializedProperty m_ScriptableRenderLoop; + SerializedProperty m_LogWhenShaderIsCompiled; Object graphicsSettings { @@ -77,6 +79,7 @@ public void OnEnable() m_TransparencySortMode = serializedObject.FindProperty("m_TransparencySortMode"); m_TransparencySortAxis = serializedObject.FindProperty("m_TransparencySortAxis"); m_ScriptableRenderLoop = serializedObject.FindProperty("m_CustomRenderPipeline"); + m_LogWhenShaderIsCompiled = serializedObject.FindProperty("m_LogWhenShaderIsCompiled"); tierSettingsAnimator = new AnimatedValues.AnimBool(showTierSettingsUI, Repaint); } @@ -166,6 +169,7 @@ public override void OnInspectorGUI() EditorGUILayout.Space(); GUILayout.Label(Styles.shaderPreloadSettings, EditorStyles.boldLabel); + EditorGUILayout.PropertyField(m_LogWhenShaderIsCompiled, Styles.logWhenShaderIsCompiled); shaderPreloadEditor.OnInspectorGUI(); serializedObject.ApplyModifiedProperties(); diff --git a/Editor/Mono/Inspector/InspectorElement.cs b/Editor/Mono/Inspector/InspectorElement.cs index f7c6ec066f..e7bb8263de 100644 --- a/Editor/Mono/Inspector/InspectorElement.cs +++ b/Editor/Mono/Inspector/InspectorElement.cs @@ -61,6 +61,7 @@ internal Editor editor { DestroyOwnedEditor(); m_Editor = value; + ownsEditor = false; PartialReset(); } } @@ -267,8 +268,12 @@ private Editor GetOrCreateEditor(SerializedObject serializedObject) } RegisterCallback(OnDetachFromPanel); + + var ed = Editor.CreateEditor(serializedObject?.targetObject); + editor = ed; ownsEditor = true; - return editor = Editor.CreateEditor(serializedObject?.targetObject); + + return ed; } private VisualElement CreateDefaultInspector(SerializedObject serializedObject) @@ -315,6 +320,34 @@ bool AddMissingScriptLabel(SerializedObject serializedObject) return false; } + internal static bool SetWideModeForWidth(VisualElement displayElement) + { + var previousWideMode = EditorGUIUtility.wideMode; + + float inspectorWidth = 0; + + // the inspector's width can be NaN if this is our first layout check. + // or when the inspector display is changed from none to flex, the width will be zero during the measuring phase. + // we try to find a parent with a a width. If none are found, we'll set wideMode to true to avoid computing + // too tall an inspector on the first layout calculation + while (displayElement != null && (float.IsNaN(inspectorWidth) || inspectorWidth == 0)) + { + inspectorWidth = displayElement.layout.width; + displayElement = displayElement.hierarchy.parent; + } + + if (!float.IsNaN(inspectorWidth) && inspectorWidth > 0) + { + EditorGUIUtility.wideMode = inspectorWidth > Editor.k_WideModeMinWidth; + } + else + { + EditorGUIUtility.wideMode = true; + } + + return previousWideMode; + } + IMGUIContainer m_IMGUIContainer; private VisualElement CreateIMGUIInspectorFromEditor(SerializedObject serializedObject, Editor editor, @@ -425,23 +458,12 @@ private VisualElement CreateIMGUIInspectorFromEditor(SerializedObject serialized //set the current PropertyHandlerCache to the current editor ScriptAttributeUtility.propertyHandlerCache = editor.propertyHandlerCache; - var originalWideMode = EditorGUIUtility.wideMode; var originalHierarchyMode = EditorGUIUtility.hierarchyMode; - EditorGUIUtility.hierarchyMode = true; - var inspectorWidth = inspector.layout.width; - // the inspector's width can be NaN if this is our first layout check. - // If that's the case we'll set wideMode to true to avoid computing too tall an inspector on the first layout calculation - if (!float.IsNaN(inspectorWidth)) - { - EditorGUIUtility.wideMode = inspectorWidth > Editor.k_WideModeMinWidth; - } - else - { - EditorGUIUtility.wideMode = true; - } - GUIStyle editorWrapper = (editor.UseDefaultMargins() + var originalWideMode = SetWideModeForWidth(inspector); + + GUIStyle editorWrapper = (editor.UseDefaultMargins() && editor.CanBeExpandedViaAFoldout() ? EditorStyles.inspectorDefaultMargins : GUIStyle.none); try @@ -499,6 +521,14 @@ private VisualElement CreateIMGUIInspectorFromEditor(SerializedObject serialized } finally { + if (GUI.changed) + { + // This forces a relayout of all imguicontainers in this inspector window. + // fixes part of case 1148706 + var element = inspector.GetFirstAncestorOfType(); + if (element != null) + EditorElement.InvalidateIMGUILayouts(element.parent); + } EditorGUIUtility.wideMode = originalWideMode; EditorGUIUtility.hierarchyMode = originalHierarchyMode; } diff --git a/Editor/Mono/Inspector/InspectorWindow.cs b/Editor/Mono/Inspector/InspectorWindow.cs index 85d6275b65..4b881942fa 100644 --- a/Editor/Mono/Inspector/InspectorWindow.cs +++ b/Editor/Mono/Inspector/InspectorWindow.cs @@ -24,6 +24,7 @@ using Overflow = UnityEngine.UIElements.Overflow; using AssetImporterEditor = UnityEditor.Experimental.AssetImporters.AssetImporterEditor; +using UnityEditor.SceneManagement; namespace UnityEditor { @@ -54,6 +55,7 @@ internal InspectorMode inspectorMode const float k_InspectorPreviewMinTotalHeight = k_InspectorPreviewMinHeight + kBottomToolbarHeight; const int k_MinimumRootVisualHeight = 81; const int k_MinimumWindowWidth = 275; + const int k_AutoScrollZoneHeight = 24; private const long delayRepaintWhilePlayingAnimation = 150; // Delay between repaints in milliseconds while playing animation private long s_LastUpdateWhilePlayingAnimation = 0; @@ -107,6 +109,10 @@ internal InspectorMode inspectorMode VisualElement m_MultiEditLabel; + ScrollView m_ScrollView; + [SerializeField] int m_LastInspectedObjectInstanceID = -1; + [SerializeField] float m_LastVerticalScrollValue = 0; + VisualElement FindVisualElementInTreeByClassName(string elementClassName) { var element = rootVisualElement.Q(className: elementClassName); @@ -190,6 +196,7 @@ protected virtual void OnEnable() LoadVisualTreeFromUxml(); + m_PreviewResizer.localFrame = true; m_PreviewResizer.Init("InspectorPreview"); m_LabelGUI.OnEnable(); @@ -218,6 +225,7 @@ private void LoadVisualTreeFromUxml() var container = tpl.CloneTree(); container.AddToClassList(s_MainContainerClassName); rootVisualElement.hierarchy.Add(container); + m_ScrollView = container.Q(); var multiContainer = rootVisualElement.Q(className: s_MultiEditClassName); multiContainer.Query().ForEach((label) => label.text = L10n.Tr(label.text)); @@ -240,6 +248,7 @@ void OnGeometryChanged(GeometryChangedEvent e) m_PreviewResizer.SetExpanded(false); } } + RestoreVerticalScrollIfNeeded(); } private void OnProjectWasLoaded() @@ -268,6 +277,10 @@ private void OnProjectWasLoaded() protected virtual void OnDisable() { + // save vertical scroll position + m_LastInspectedObjectInstanceID = GetInspectedObject()?.GetInstanceID() ?? -1; + m_LastVerticalScrollValue = m_ScrollView?.verticalScroller.value ?? 0; + RemoveInspectorWindow(this); m_LockTracker?.lockStateChanged.RemoveListener(LockStateChanged); @@ -509,15 +522,19 @@ void ExtractPrefabComponents() return; if (m_Tracker.activeEditors[0].targets.Length != 1) return; + GameObject go = m_Tracker.activeEditors[0].target as GameObject; + if (go == null && m_Tracker.activeEditors[0] is PrefabImporterEditor) + go = m_Tracker.activeEditors[1].target as GameObject; if (go == null) return; + GameObject sourceGo = PrefabUtility.GetCorrespondingConnectedObjectFromSource(go); if (sourceGo == null) return; m_ComponentsInPrefabSource = sourceGo.GetComponents(); - var removedComponentsList = PrefabUtility.GetRemovedComponents(PrefabUtility.GetOutermostPrefabInstanceRoot(go)); + var removedComponentsList = PrefabOverridesUtility.GetRemovedComponentsForSingleGameObject(go); for (int i = 0; i < removedComponentsList.Count; i++) { m_RemovedComponents.Add(removedComponentsList[i].assetComponent); @@ -678,6 +695,12 @@ internal virtual void RebuildContentsContainers() var labelMustBeAdded = m_MultiEditLabel.parent != editorsElement; + // The PrefabImporterEditor can hide its imported objects if it detects missing scripts. In this case + // do not add the multi editing warning + var assetImporter = GetAssetImporter(editors); + if (assetImporter != null && !assetImporter.showImportedObject) + labelMustBeAdded = false; + if (tracker.hasComponentsWhichCannotBeMultiEdited) { Profiler.BeginSample("InspectorWindow.RebuildContentsContainers()::hasComponentsWhichCannotBeMultiEdited"); @@ -758,6 +781,21 @@ void DragOverBottomArea(DragUpdatedEvent dragUpdatedEvent) { if (editorsElement.ContainsPoint(dragUpdatedEvent.mousePosition)) { + if (m_ScrollView != null) + { + // implement auto-scroll for easier component drag'n'drop, + // we define a zone of height = k_AutoScrollZoneHeight + // at the top/bottom of the scrollView viewport, + // while dragging, when the mouse moves in these zones, + // we automatically scroll up/down + var localDragPosition = m_ScrollView.contentViewport.WorldToLocal(dragUpdatedEvent.mousePosition); + + if (localDragPosition.y < k_AutoScrollZoneHeight) + m_ScrollView.verticalScroller.ScrollPageUp(); + else if (localDragPosition.y > m_ScrollView.contentViewport.rect.height - k_AutoScrollZoneHeight) + m_ScrollView.verticalScroller.ScrollPageDown(); + } + return; } @@ -1378,13 +1416,26 @@ void DrawEditors(Editor[] editors) if (editors.Length > 0 && editors[0].GetInstanceID() != m_LastInitialEditorInstanceID) OnTrackerRebuilt(); + if (m_RemovedComponents == null) + ExtractPrefabComponents(); // needed after assembly reload (due to HashSet not being serializable) + + bool checkForRemovedComponents = m_ComponentsInPrefabSource != null; int prefabComponentIndex = -1; + int targetGameObjectIndex = -1; + GameObject targetGameObject = null; + if (checkForRemovedComponents) + { + targetGameObjectIndex = editors[0] is PrefabImporterEditor ? 1 : 0; + targetGameObject = (GameObject)editors[targetGameObjectIndex].target; + } for (int editorIndex = 0; editorIndex < editors.Length; editorIndex++) { VisualElement prefabsComponentElement = new VisualElement() { name = "PrefabComponentElement" }; - if (m_ComponentsInPrefabSource != null && editorIndex != 0) + if (checkForRemovedComponents && editorIndex > targetGameObjectIndex) { + if (prefabComponentIndex == -1) + prefabComponentIndex = 0; while (prefabComponentIndex < m_ComponentsInPrefabSource.Length) { Object target = editors[editorIndex].target; @@ -1396,15 +1447,13 @@ void DrawEditors(Editor[] editors) if (correspondingSource == nextInSource) break; - AddRemovedPrefabComponentElement(editors, nextInSource, prefabsComponentElement); + AddRemovedPrefabComponentElement(targetGameObject, nextInSource, prefabsComponentElement); } - prefabComponentIndex++; } + prefabComponentIndex++; } - prefabComponentIndex++; - if (ShouldCullEditor(editors, editorIndex)) { editors[editorIndex].isInspectorDirty = false; @@ -1413,33 +1462,44 @@ void DrawEditors(Editor[] editors) var editor = editors[editorIndex]; Object editorTarget = editor.targets[0]; + string editorTitle = ObjectNames.GetInspectorTitle(editorTarget); EditorElement editorContainer; - if (mapping == null || !mapping.TryGetValue(editors[editorIndex].target.GetInstanceID(), out editorContainer)) + try { - editorContainer = new EditorElement(editorIndex, this) { name = editorTitle }; - editorsElement.Add(editorContainer); - } + if (mapping == null || !mapping.TryGetValue(editors[editorIndex].target.GetInstanceID(), out editorContainer)) + { + editorContainer = new EditorElement(editorIndex, this) { name = editorTitle }; + editorsElement.Add(editorContainer); + } - if (prefabsComponentElement.childCount > 0) - { - editorContainer.AddPrefabComponent(prefabsComponentElement); + if (prefabsComponentElement.childCount > 0) + { + editorContainer.AddPrefabComponent(prefabsComponentElement); + } + else + { + editorContainer.AddPrefabComponent(null); + } } - else + catch (Editor.SerializedObjectNotCreatableException) { - editorContainer.AddPrefabComponent(null); + // This can happen after a domain reload when the + // target is a pure c# object, like a MonoBehaviour + // We'll just attempt to recreate the EditorElement on the next frame + // see case 1147234 } } // Make sure to display any remaining removed components that come after the last component on the GameObject. - if (m_ComponentsInPrefabSource != null) + if (checkForRemovedComponents) { VisualElement prefabsComponentElement = new VisualElement() { name = "RemainingPrefabComponentElement" }; while (prefabComponentIndex < m_ComponentsInPrefabSource.Length) { Component nextInSource = m_ComponentsInPrefabSource[prefabComponentIndex]; - AddRemovedPrefabComponentElement(editors, nextInSource, prefabsComponentElement); + AddRemovedPrefabComponentElement(targetGameObject, nextInSource, prefabsComponentElement); prefabComponentIndex++; } @@ -1452,9 +1512,18 @@ void DrawEditors(Editor[] editors) } } - void AddRemovedPrefabComponentElement(Editor[] editors, Component nextInSource, VisualElement element) + void RestoreVerticalScrollIfNeeded() + { + if (m_LastInspectedObjectInstanceID == -1) + return; + var inspectedObjectInstanceID = GetInspectedObject()?.GetInstanceID() ?? -1; + if (inspectedObjectInstanceID == m_LastInspectedObjectInstanceID && inspectedObjectInstanceID != -1) + m_ScrollView.verticalScroller.value = m_LastVerticalScrollValue; + m_LastInspectedObjectInstanceID = -1; // reset to make sure the restore occurs once + } + + void AddRemovedPrefabComponentElement(GameObject targetGameObject, Component nextInSource, VisualElement element) { - var targetGameObject = editors[0].target as GameObject; if (ShouldDisplayRemovedComponent(targetGameObject, nextInSource)) { string missingComponentTitle = ObjectNames.GetInspectorTitle(nextInSource); @@ -1560,6 +1629,10 @@ internal bool ShouldCullEditor(Editor[] editors, int editorIndex) Object currentTarget = editors[editorIndex].target; + // Editors that should always be hidden + if (currentTarget is ParticleSystemRenderer) + return true; + // Hide regular AssetImporters (but not inherited types) if (currentTarget != null && currentTarget.GetType() == typeof(AssetImporter)) return true; @@ -1567,7 +1640,7 @@ internal bool ShouldCullEditor(Editor[] editors, int editorIndex) // Let asset importers decide if the imported object should be shown or not if (m_InspectorMode == InspectorMode.Normal && editorIndex != 0) { - AssetImporterEditor importerEditor = editors[0] as AssetImporterEditor; + AssetImporterEditor importerEditor = GetAssetImporter(editors); if (importerEditor != null && !importerEditor.showImportedObject) return true; } @@ -1607,10 +1680,23 @@ void DrawSelectionPickerList() EditorGUIUtility.SetIconSize(oldSize); } + AssetImporterEditor GetAssetImporter(Editor[] editors) + { + if (editors == null || editors.Length == 0) + return null; + + return editors[0] as AssetImporterEditor; + } + private void AddComponentButton(Editor[] editors) { + // Don't show the Add Component button if we are not showing imported objects for Asset Importers + var assetImporter = GetAssetImporter(editors); + if (assetImporter != null && !assetImporter.showImportedObject) + return; + Editor editor = InspectorWindowUtils.GetFirstNonImportInspectorEditor(editors); - if (editor != null && editor.target != null && editor.target is GameObject && editor.IsEnabled() && !EditorUtility.IsPersistent(editor.target)) + if (editor != null && editor.target != null && editor.target is GameObject && editor.IsEnabled()) { EditorGUILayout.BeginHorizontal(GUIContent.none, GUIStyle.none, GUILayout.Height(kAddComponentButtonHeight)); { @@ -1831,15 +1917,15 @@ Dictionary ProcessEditorElementsToRebuild(Editor[] editors) continue; } - if (ed.GetType() != currentEd.editor.GetType()) + // We won't have an EditorElement for editors that are normally culled so we should skip this + if (ShouldCullEditor(editors, newEditorsIndex)) { - // We won't have an EditorElement for editors that are normally culled so we should skip this - if (ShouldCullEditor(editors, newEditorsIndex)) - { - ++newEditorsIndex; - continue; - } + ++newEditorsIndex; + continue; + } + if (ed.target != currentEd.editor.target) + { return null; } diff --git a/Editor/Mono/Inspector/LightProbeGroupInspector.cs b/Editor/Mono/Inspector/LightProbeGroupInspector.cs index d8fbafac9b..6c610f2810 100644 --- a/Editor/Mono/Inspector/LightProbeGroupInspector.cs +++ b/Editor/Mono/Inspector/LightProbeGroupInspector.cs @@ -24,6 +24,7 @@ internal class LightProbeGroupEditor : IEditablePoint private readonly LightProbeGroup m_Group; private bool m_ShouldRecalculateTetrahedra; + private bool m_SourcePositionsDirty; private Vector3 m_LastPosition = Vector3.zero; private Quaternion m_LastRotation = Quaternion.identity; private Vector3 m_LastScale = Vector3.one; @@ -34,7 +35,8 @@ internal class LightProbeGroupEditor : IEditablePoint public LightProbeGroupEditor(LightProbeGroup group, LightProbeGroupInspector inspector) { m_Group = group; - MarkTetrahedraDirty(); + m_ShouldRecalculateTetrahedra = false; + m_SourcePositionsDirty = false; m_SerializedSelectedProbes = ScriptableObject.CreateInstance(); m_SerializedSelectedProbes.hideFlags = HideFlags.HideAndDontSave; m_Inspector = inspector; @@ -52,7 +54,7 @@ public void AddProbe(Vector3 position) m_SourcePositions.Add(position); SelectProbe(m_SourcePositions.Count - 1); - MarkTetrahedraDirty(); + MarkSourcePositionsDirty(); } private void SelectProbe(int i) @@ -93,7 +95,7 @@ public void DuplicateSelectedProbes() m_SourcePositions.Add(position); } - MarkTetrahedraDirty(); + MarkSourcePositionsDirty(); } private void CopySelectedProbes() @@ -153,7 +155,7 @@ private bool PasteProbes() { SelectProbe(i); } - MarkTetrahedraDirty(); + MarkSourcePositionsDirty(); return true; } @@ -177,7 +179,7 @@ public void RemoveSelectedProbes() m_SourcePositions.RemoveAt(index); } DeselectProbes(); - MarkTetrahedraDirty(); + MarkSourcePositionsDirty(); } public void PullProbePositions() @@ -191,7 +193,12 @@ public void PullProbePositions() public void PushProbePositions() { - m_Group.probePositions = m_SourcePositions.ToArray(); + if (m_SourcePositionsDirty) + { + m_Group.probePositions = m_SourcePositions.ToArray(); + m_SourcePositionsDirty = false; + } + m_SerializedSelectedProbes.m_Selection = m_Selection; } @@ -301,7 +308,7 @@ public bool OnSceneGUI(Transform transform) || m_LastRotation != m_Group.transform.rotation || m_LastScale != m_Group.transform.localScale) { - MarkTetrahedraDirty(); + MarkSourcePositionsDirty(); } m_LastPosition = m_Group.transform.position; @@ -311,6 +318,7 @@ public bool OnSceneGUI(Transform transform) //See if we should enter edit mode! bool firstSelect = false; + if (Event.current.type == EventType.MouseDown && Event.current.button == 0) { //We have no probes selected and have clicked the mouse... Did we click a probe @@ -373,20 +381,21 @@ public bool OnSceneGUI(Transform transform) { Undo.RegisterCompleteObjectUndo(new Object[] { m_Group, m_SerializedSelectedProbes }, "Move Probes"); if (LightProbeVisualization.dynamicUpdateLightProbes) - MarkTetrahedraDirty(); + MarkSourcePositionsDirty(); } if (m_Editing && mouseUpEvent && !LightProbeVisualization.dynamicUpdateLightProbes) { - MarkTetrahedraDirty(); + MarkSourcePositionsDirty(); } return m_Editing; } - public void MarkTetrahedraDirty() + public void MarkSourcePositionsDirty() { m_ShouldRecalculateTetrahedra = true; + m_SourcePositionsDirty = true; } public Bounds selectedProbeBounds @@ -433,6 +442,7 @@ public void SetPosition(int idx, Vector3 position) return; m_SourcePositions[idx] = position; + MarkSourcePositionsDirty(); } private static readonly Color kCloudColor = new Color(200f / 255f, 200f / 255f, 20f / 255f, 0.85f); @@ -470,6 +480,8 @@ public void UpdateSelectedPosition(int idx, Vector3 position) return; m_SourcePositions[m_Selection[idx]] = position; + + MarkSourcePositionsDirty(); } public IEnumerable GetPositions() @@ -627,7 +639,7 @@ private void UndoRedoPerformed() // Update the cached probe positions from the ones just restored in the LightProbeGroup m_Editor.PullProbePositions(); - m_Editor.MarkTetrahedraDirty(); + m_Editor.MarkSourcePositionsDirty(); } private bool m_EditingProbes; @@ -710,7 +722,7 @@ public override void OnInspectorGUI() if (EditorGUI.EndChangeCheck()) { - m_Editor.MarkTetrahedraDirty(); + m_Editor.MarkSourcePositionsDirty(); SceneView.RepaintAll(); } } diff --git a/Editor/Mono/Inspector/LightProbeProxyVolumeEditor.cs b/Editor/Mono/Inspector/LightProbeProxyVolumeEditor.cs index b849130b70..747aaa9f79 100644 --- a/Editor/Mono/Inspector/LightProbeProxyVolumeEditor.cs +++ b/Editor/Mono/Inspector/LightProbeProxyVolumeEditor.cs @@ -44,7 +44,7 @@ static Styles() } public static GUIStyle richTextMiniLabel = new GUIStyle(EditorStyles.miniLabel); - public static GUIContent volumeResolutionText = EditorGUIUtility.TrTextContent("Proxy Volume Resolution", "Specifies the resolution of the 3D grid of interpolated light probes. Higher resolution/density means better lighting but the CPU cost will increase."); + public static GUIContent volumeResolutionText = EditorGUIUtility.TrTextContent("Proxy Volume Resolution", "Specifies the resolution of the 3D grid of interpolated light probes. Higher resolution/density means better lighting, but the CPU cost will increase."); public static GUIContent resolutionXText = new GUIContent("X"); public static GUIContent resolutionYText = new GUIContent("Y"); public static GUIContent resolutionZText = new GUIContent("Z"); @@ -52,10 +52,10 @@ static Styles() public static GUIContent bbSettingsText = EditorGUIUtility.TrTextContent("Bounding Box Settings"); public static GUIContent originText = EditorGUIUtility.TrTextContent("Origin"); public static GUIContent bbModeText = EditorGUIUtility.TrTextContent("Bounding Box Mode", "The mode in which the bounding box is computed. A 3D grid of interpolated light probes will be generated inside this bounding box.\n\nAutomatic Local - the local-space bounding box of the Renderer is used.\n\nAutomatic Global - a bounding box is computed which encloses the current Renderer and all the Renderers down the hierarchy that have the Light Probes property set to Use Proxy Volume. The bounding box will be world-space aligned.\n\nCustom - a custom bounding box is used. The bounding box is specified in the local-space of the game object."); - public static GUIContent resModeText = EditorGUIUtility.TrTextContent("Resolution Mode", "The mode in which the resolution of the 3D grid of interpolated light probes is specified:\n\nAutomatic - the resolution on each axis is computed using a user-specified number of interpolated light probes per unit area(Density).\n\nCustom - the user can specify a different resolution on each axis."); + public static GUIContent resModeText = EditorGUIUtility.TrTextContent("Resolution Mode", "The mode in which the resolution of the 3D grid of interpolated light probes is specified:\n\nAutomatic - the resolution on each axis is computed using a user-specified number of interpolated light probes per unit area (Density).\n\nCustom - the user can specify a different resolution on each axis."); public static GUIContent probePositionText = EditorGUIUtility.TrTextContent("Probe Position Mode", "The mode in which the interpolated probe positions are generated.\n\nCellCorner - divide the volume in cells and generate interpolated probe positions in the corner/edge of the cells.\n\nCellCenter - divide the volume in cells and generate interpolated probe positions in the center of the cells."); public static GUIContent refreshModeText = EditorGUIUtility.TrTextContent("Refresh Mode"); - public static GUIContent qualityText = EditorGUIUtility.TrTextContent("Quality", "Affects the total number of evaluated Spherical Harmonics(SH) bands for Renderers that use a Light Probe Proxy Volume:\n\nLow Quality - uses only 2 bands(L0 and L1) sampled from a LPPV texture. This option might improve the performance by not breaking batching.\n\nNormal Quality - uses all the bands to evaluate the SH. L0 and L1 are sampled from a LPPV texture and L2 is constant per Renderer."); + public static GUIContent qualityText = EditorGUIUtility.TrTextContent("Quality", "Affects the total number of evaluated Spherical Harmonics(SH) bands for Renderers that use a Light Probe Proxy Volume:\n\nLow Quality - uses only 2 bands (L0 and L1) sampled from a LPPV texture. This option might improve the performance by not breaking batching.\n\nNormal Quality - uses all the bands to evaluate the SH. L0 and L1 are sampled from a LPPV texture and L2 is constant per Renderer."); public static GUIContent[] bbMode = (Enum.GetNames(typeof(LightProbeProxyVolume.BoundingBoxMode)).Select(x => ObjectNames.NicifyVariableName(x)).ToArray()).Select(x => new GUIContent(x)).ToArray(); public static GUIContent[] resMode = (Enum.GetNames(typeof(LightProbeProxyVolume.ResolutionMode)).Select(x => ObjectNames.NicifyVariableName(x)).ToArray()).Select(x => new GUIContent(x)).ToArray(); public static GUIContent[] probePositionMode = (Enum.GetNames(typeof(LightProbeProxyVolume.ProbePositionMode)).Select(x => ObjectNames.NicifyVariableName(x)).ToArray()).Select(x => new GUIContent(x)).ToArray(); diff --git a/Editor/Mono/Inspector/LightingSettingsInspector.cs b/Editor/Mono/Inspector/LightingSettingsInspector.cs index 22679222dc..822fe7ede3 100644 --- a/Editor/Mono/Inspector/LightingSettingsInspector.cs +++ b/Editor/Mono/Inspector/LightingSettingsInspector.cs @@ -36,7 +36,7 @@ static class Styles public static readonly GUIContent MinimumChartSize = EditorGUIUtility.TrTextContent("Min Chart Size", "Specifies the minimum texel size used for a UV chart. If stitching is required, a value of 4 will create a chart of 4x4 texels to store lighting and directionality. If stitching is not required, a value of 2 will reduce the texel density and provide better lighting build times and run time performance."); public static readonly GUIContent ImportantGI = EditorGUIUtility.TrTextContent("Prioritize Illumination", "When enabled, the object will be marked as a priority object and always included in lighting calculations. Useful for objects that will be strongly emissive to make sure that other objects will be illuminated by this object."); public static readonly GUIContent StitchLightmapSeams = EditorGUIUtility.TrTextContent("Stitch Seams", "When enabled, seams in baked lightmaps will get smoothed."); - public static readonly GUIContent AutoUVMaxDistance = EditorGUIUtility.TrTextContent("Max Distance", "Specifies the maximum worldspace distance to be used for UV chart simplification. If charts are within this distance they will be simplified for optimization purposes."); + public static readonly GUIContent AutoUVMaxDistance = EditorGUIUtility.TrTextContent("Max Distance", "Specifies the maximum worldspace distance to be used for UV chart simplification. If charts are within this distance, they will be simplified for optimization purposes."); public static readonly GUIContent AutoUVMaxAngle = EditorGUIUtility.TrTextContent("Max Angle", "Specifies the maximum angle in degrees between faces sharing a UV edge. If the angle between the faces is below this value, the UV charts will be simplified."); public static readonly GUIContent LightmapParameters = EditorGUIUtility.TrTextContent("Lightmap Parameters", "Allows the adjustment of advanced parameters that affect the process of generating a lightmap for an object using global illumination."); public static readonly GUIContent AtlasTilingX = EditorGUIUtility.TrTextContent("Tiling X"); diff --git a/Editor/Mono/Inspector/LineRendererCurveEditor.cs b/Editor/Mono/Inspector/LineRendererCurveEditor.cs index e99a67f068..84a4b50193 100644 --- a/Editor/Mono/Inspector/LineRendererCurveEditor.cs +++ b/Editor/Mono/Inspector/LineRendererCurveEditor.cs @@ -100,6 +100,9 @@ private void UndoRedoPerformed() public void CheckCurveChangedExternally() { + if (Event.current.type != EventType.Repaint) + return; + CurveWrapper cw = m_Editor.GetCurveWrapperFromID(0); if (m_WidthCurve != null) { @@ -110,10 +113,24 @@ public void CheckCurveChangedExternally() } else if (cw != null) { - if (cw.curve.length == 0) - m_Refresh = true; - else if (propCurve.length >= 1 && propCurve.keys[0].value != cw.curve.keys[0].value) + if (cw.curve.length == 0 || cw.curve.length != propCurve.length) + { m_Refresh = true; + } + else + { + var curveKeys = cw.curve.keys; + var propKeys = propCurve.keys; + + for (int i = 0; i < curveKeys.Length; i++) + { + if (!propKeys[i].Equals(curveKeys[i])) + { + m_Refresh = true; + break; + } + } + } } } else if (cw != null) diff --git a/Editor/Mono/Inspector/LineRendererEditor.cs b/Editor/Mono/Inspector/LineRendererEditor.cs index d4381006b0..bb4db687c9 100644 --- a/Editor/Mono/Inspector/LineRendererEditor.cs +++ b/Editor/Mono/Inspector/LineRendererEditor.cs @@ -26,7 +26,7 @@ class Styles public static readonly GUIContent normalOffset = EditorGUIUtility.TrTextContent("Offset", "The offset applied to created points either from the scene camera or raycast normal, when using physics."); public static readonly GUIContent numCapVertices = EditorGUIUtility.TrTextContent("End Cap Vertices", "How many vertices to add at each end."); public static readonly GUIContent numCornerVertices = EditorGUIUtility.TrTextContent("Corner Vertices", "How many vertices to add for each corner."); - public static readonly GUIContent pointSeparation = EditorGUIUtility.TrTextContent("Min Vertex Distance", "When dragging the mouse a new point will be created after the distance has been exceeded."); + public static readonly GUIContent pointSeparation = EditorGUIUtility.TrTextContent("Min Vertex Distance", "When dragging the mouse, a new point will be created after the distance has been exceeded."); public static readonly GUIContent positions = EditorGUIUtility.TrTextContent("Positions"); public static readonly GUIContent propertyMenuContent = EditorGUIUtility.TrTextContent("Delete Selected Array Elements"); public static readonly GUIContent showWireframe = EditorGUIUtility.TrTextContent("Show Wireframe", "Show the wireframe visualizing the line."); @@ -463,6 +463,11 @@ private void InternalOnSceneView() { case EditMode.SceneViewEditMode.LineRendererEdit: m_PointEditor.EditSceneGUI(); + + // We need to wait for m_Positions to be updated next frame or we risk calling SetSelection with invalid indexes. + if (m_PointEditor.Count != m_Positions.arraySize) + break; + if (m_Positions.arraySize != m_PositionsView.GetRows().Count) { m_PositionsView.Reload(); diff --git a/Editor/Mono/Inspector/MaterialEditor.cs b/Editor/Mono/Inspector/MaterialEditor.cs index 528c3b6613..8f6d5f1ec6 100644 --- a/Editor/Mono/Inspector/MaterialEditor.cs +++ b/Editor/Mono/Inspector/MaterialEditor.cs @@ -1542,25 +1542,31 @@ public bool DidModifyAnimationModeMaterialProperty(MaterialProperty property, in static Renderer[] GetAssociatedRenderersFromInspector() { - List renderers = new List(); var imguicontainer = UIElementsUtility.GetCurrentIMGUIContainer(); if (imguicontainer != null) { var editorElement = imguicontainer.GetFirstAncestorOfType(); if (editorElement != null) { - foreach (var editor in editorElement.Editors) - { - foreach (Object target in editor.targets) - { - var renderer = target as Renderer; - if (renderer) - renderers.Add(renderer); - } - } + return GetAssociatedRenderersFromEditors(editorElement.Editors); } } + return new Renderer[0]; + } + + internal static Renderer[] GetAssociatedRenderersFromEditors(IEnumerable editors) + { + List renderers = new List(); + foreach (var editor in editors) + { + foreach (Object target in editor.targets) + { + var renderer = target as Renderer; + if (renderer) + renderers.Add(renderer); + } + } return renderers.ToArray(); } diff --git a/Editor/Mono/Inspector/ModelInspector.cs b/Editor/Mono/Inspector/ModelInspector.cs index d23c23c396..85efa5d546 100644 --- a/Editor/Mono/Inspector/ModelInspector.cs +++ b/Editor/Mono/Inspector/ModelInspector.cs @@ -211,7 +211,7 @@ public override string GetInfoString() info += ", " + submeshes + " submeshes"; int blendShapeCount = mesh.blendShapeCount; - if (blendShapeCount > 1) + if (blendShapeCount > 0) info += ", " + blendShapeCount + " blendShapes"; info += "\n" + InternalMeshUtil.GetVertexFormat(mesh); diff --git a/Editor/Mono/Inspector/MonoScriptInspector.cs b/Editor/Mono/Inspector/MonoScriptInspector.cs index 93e74e1ef8..bce4e6bdcf 100644 --- a/Editor/Mono/Inspector/MonoScriptInspector.cs +++ b/Editor/Mono/Inspector/MonoScriptInspector.cs @@ -161,6 +161,11 @@ internal class TextAssetInspector : Editor [NonSerialized] private GUIStyle m_TextStyle; + public virtual void OnEnable() + { + alwaysAllowExpansion = true; + } + public override void OnInspectorGUI() { if (m_TextStyle == null) diff --git a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs index 7507d834bf..c1d7d5bebc 100644 --- a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs +++ b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs @@ -60,7 +60,7 @@ class SettingsContent public static readonly GUIContent cursorHotspot = EditorGUIUtility.TrTextContent("Cursor Hotspot"); public static readonly GUIContent defaultCursor = EditorGUIUtility.TrTextContent("Default Cursor"); public static readonly GUIContent defaultIcon = EditorGUIUtility.TrTextContent("Default Icon"); - public static readonly GUIContent vertexChannelCompressionMask = EditorGUIUtility.TrTextContent("Vertex Compression*", "Select which vertex channels should be compressed. Compression can save memory and bandwidth but precision will be lower."); + public static readonly GUIContent vertexChannelCompressionMask = EditorGUIUtility.TrTextContent("Vertex Compression*", "Select which vertex channels should be compressed. Compression can save memory and bandwidth, but precision will be lower."); public static readonly GUIContent iconTitle = EditorGUIUtility.TrTextContent("Icon"); public static readonly GUIContent resolutionPresentationTitle = EditorGUIUtility.TrTextContent("Resolution and Presentation"); @@ -119,6 +119,7 @@ class SettingsContent public static readonly GUIContent displayResolutionDialogDeprecationWarning = EditorGUIUtility.TrTextContent("The Display Resolution Dialog has been deprecated and will be removed in a future version."); public static readonly GUIContent visibleInBackground = EditorGUIUtility.TrTextContent("Visible In Background"); public static readonly GUIContent allowFullscreenSwitch = EditorGUIUtility.TrTextContent("Allow Fullscreen Switch"); + public static readonly GUIContent useFlipModelSwapChain = EditorGUIUtility.TrTextContent("Use DXGI Flip Model Swapchain for D3D11", "Flip model ensures the best performance. Disable this to fallback to Windows 7-style BltBlt model. This setting affects only D3D11 graphics API."); public static readonly GUIContent use32BitDisplayBuffer = EditorGUIUtility.TrTextContent("Use 32-bit Display Buffer*", "If set Display Buffer will be created to hold 32-bit color values. Use it only if you see banding, as it has performance implications."); public static readonly GUIContent disableDepthAndStencilBuffers = EditorGUIUtility.TrTextContent("Disable Depth and Stencil*"); public static readonly GUIContent preserveFramebufferAlpha = EditorGUIUtility.TrTextContent("Render Over Native UI*", "Enable this option ONLY if you want Unity to render on top of the native Android or iOS UI."); @@ -144,7 +145,7 @@ class SettingsContent public static readonly GUIContent graphicsJobsMode = EditorGUIUtility.TrTextContent("Graphics Jobs Mode*"); public static readonly GUIContent applicationBuildNumber = EditorGUIUtility.TrTextContent("Build"); public static readonly GUIContent appleDeveloperTeamID = EditorGUIUtility.TrTextContent("iOS Developer Team ID", "Developers can retrieve their Team ID by visiting the Apple Developer site under Account > Membership."); - public static readonly GUIContent useOnDemandResources = EditorGUIUtility.TrTextContent("Use on demand resources*"); + public static readonly GUIContent useOnDemandResources = EditorGUIUtility.TrTextContent("Use on-demand resources*"); public static readonly GUIContent gcIncremental = EditorGUIUtility.TrTextContent("Use incremental GC (Experimental)", "With incremental Garbage Collection, the Garbage Collector will try to time-slice the collection task into multiple steps, to avoid long GC times preventing content from running smoothly."); public static readonly GUIContent accelerometerFrequency = EditorGUIUtility.TrTextContent("Accelerometer Frequency*"); public static readonly GUIContent cameraUsageDescription = EditorGUIUtility.TrTextContent("Camera Usage Description*", "String shown to the user when requesting permission to use the device camera. Written to the NSCameraUsageDescription field in Xcode project's info.plist file"); @@ -189,8 +190,8 @@ class SettingsContent public static readonly GUIContent[] activeInputHandlingOptions = new GUIContent[] { EditorGUIUtility.TrTextContent("Input Manager"), EditorGUIUtility.TrTextContent("Input System (Preview)"), EditorGUIUtility.TrTextContent("Both") }; public static readonly GUIContent lightmapEncodingLabel = EditorGUIUtility.TrTextContent("Lightmap Encoding", "Affects the encoding scheme and compression format of the lightmaps."); public static readonly GUIContent[] lightmapEncodingNames = { EditorGUIUtility.TrTextContent("Low Quality"), EditorGUIUtility.TrTextContent("Normal Quality"), EditorGUIUtility.TrTextContent("High Quality")}; - public static readonly GUIContent lightmapStreamingEnabled = EditorGUIUtility.TrTextContent("Lightmap Streaming Enabled", "Only load larger lightmap mip maps as needed to render the current game cameras. Requires texture streaming to be enabled in quality settings. This value is applied to the light map textures as they are generated."); - public static readonly GUIContent lightmapStreamingPriority = EditorGUIUtility.TrTextContent("Streaming Priority", "Lightmap mip map streaming priority when there's contention for resources. Positive numbers represent higher priority. Valid range is -128 to 127. This value is applied to the light map textures as they are generated."); + public static readonly GUIContent lightmapStreamingEnabled = EditorGUIUtility.TrTextContent("Lightmap Streaming Enabled", "Only load larger lightmap mipmaps as needed to render the current game cameras. Requires texture streaming to be enabled in quality settings. This value is applied to the light map textures as they are generated."); + public static readonly GUIContent lightmapStreamingPriority = EditorGUIUtility.TrTextContent("Streaming Priority", "Lightmap mipmap streaming priority when there's contention for resources. Positive numbers represent higher priority. Valid range is -128 to 127. This value is applied to the light map textures as they are generated."); public static readonly GUIContent lightmapQualityAndroidWarning = EditorGUIUtility.TrTextContent("The selected Lightmap Encoding requires OpenGL ES 3.0 or Vulkan. Uncheck 'Automatic Graphics API' and remove OpenGL ES 2 API. Additionally, 'Minimum API Level' must be at least Android 4.3"); public static readonly GUIContent lightmapQualityIOSWarning = EditorGUIUtility.TrTextContent("The selected Lightmap Encoding requires Metal API only. Uncheck 'Automatic Graphics API' and remove OpenGL ES APIs."); public static readonly GUIContent monoNotSupportediOS11WarningGUIContent = EditorGUIUtility.TrTextContent("Mono is not supported on iOS11 and above."); @@ -322,6 +323,7 @@ PlayerSettingsSplashScreenEditor splashScreenEditor SerializedProperty m_VisibleInBackground; SerializedProperty m_AllowFullscreenSwitch; SerializedProperty m_ForceSingleInstance; + SerializedProperty m_UseFlipModelSwapchain; SerializedProperty m_RunInBackground; SerializedProperty m_CaptureSingleScreen; @@ -481,6 +483,7 @@ void OnEnable() m_SkinOnGPU = FindPropertyAssert("gpuSkinning"); m_GraphicsJobs = FindPropertyAssert("graphicsJobs"); m_ForceSingleInstance = FindPropertyAssert("forceSingleInstance"); + m_UseFlipModelSwapchain = FindPropertyAssert("useFlipModelSwapchain"); m_RequireES31 = FindPropertyAssert("openGLRequireES31"); m_RequireES31AEP = FindPropertyAssert("openGLRequireES31AEP"); @@ -498,10 +501,8 @@ void OnEnable() } for (int i = 0; i < m_SectionAnimators.Length; i++) - m_SectionAnimators[i] = new AnimBool(m_SelectedSection.value == i, Repaint); - - m_ShowDefaultIsNativeResolution.valueChanged.AddListener(Repaint); - m_ShowResolution.valueChanged.AddListener(Repaint); + m_SectionAnimators[i] = new AnimBool(m_SelectedSection.value == i); + SetValueChangeListeners(Repaint); m_VRSettings = new VR.PlayerSettingsEditorVR(this); @@ -512,13 +513,19 @@ void OnEnable() s_GraphicsDeviceLists.Clear(); } - public void SetSectionOpenListener(UnityAction action) + public void SetValueChangeListeners(UnityAction action) { for (int i = 0; i < m_SectionAnimators.Length; i++) { m_SectionAnimators[i].valueChanged.RemoveAllListeners(); m_SectionAnimators[i].valueChanged.AddListener(action); } + + m_ShowDefaultIsNativeResolution.valueChanged.RemoveAllListeners(); + m_ShowDefaultIsNativeResolution.valueChanged.AddListener(action); + + m_ShowResolution.valueChanged.RemoveAllListeners(); + m_ShowResolution.valueChanged.AddListener(action); } public override bool UseDefaultMargins() @@ -948,6 +955,7 @@ public void ResolutionSectionGUI(BuildTargetGroup targetGroup, ISettingEditorExt EditorGUILayout.PropertyField(m_AllowFullscreenSwitch, SettingsContent.allowFullscreenSwitch); EditorGUILayout.PropertyField(m_ForceSingleInstance); + EditorGUILayout.PropertyField(m_UseFlipModelSwapchain, SettingsContent.useFlipModelSwapChain); EditorGUILayout.PropertyField(m_SupportedAspectRatios, true); EditorGUILayout.Space(); @@ -1891,6 +1899,11 @@ internal static void ShowBuildNumberUI(SerializedObject serializedObject, BuildT } } + private bool ShouldRestartEditorToApplySetting() + { + return EditorUtility.DisplayDialog("Unity editor restart required", "The Unity editor must be restarted for this change to take effect. Cancel to revert changes.", "Apply", "Cancel"); + } + private void OtherSectionConfigurationGUI(BuildPlatform platform, BuildTargetGroup targetGroup, ISettingEditorExtension settingsExtension) { // Configuration @@ -1988,10 +2001,20 @@ private void OtherSectionConfigurationGUI(BuildPlatform platform, BuildTargetGro using (new EditorGUI.DisabledScope(!gcIncrementalEnabled)) { - if (gcIncrementalEnabled) - EditorGUILayout.PropertyField(m_GCIncremental, SettingsContent.gcIncremental); - else - EditorGUILayout.Toggle(SettingsContent.gcIncremental, false); + var oldValue = m_GCIncremental.boolValue; + EditorGUILayout.PropertyField(m_GCIncremental, SettingsContent.gcIncremental); + if (m_GCIncremental.boolValue != oldValue) + { + // Give the user a chance to change mind and revert changes. + if (ShouldRestartEditorToApplySetting()) + { + m_EnableInputSystem.serializedObject.ApplyModifiedProperties(); + if (EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo()) + EditorApplication.OpenProject(Environment.CurrentDirectory); + } + else + m_GCIncremental.boolValue = oldValue; + } } } @@ -2090,7 +2113,7 @@ private void OtherSectionConfigurationGUI(BuildPlatform platform, BuildTargetGro if (inputOption != oldInputOption) { // Give the user a chance to change mind and revert changes. - if (EditorUtility.DisplayDialog("Unity editor restart required", "The Unity editor must be restarted for this change to take effect. Cancel to revert changes.", "Apply", "Cancel")) + if (ShouldRestartEditorToApplySetting()) { m_EnableInputSystem.boolValue = (inputOption == 1 || inputOption == 2); m_DisableInputManager.boolValue = !(inputOption == 0 || inputOption == 2); @@ -2539,7 +2562,7 @@ internal static SettingsProvider CreateProjectSettingsProvider() SettingsProvider.GetSearchKeywordsFromGUIContentProperties()); provider.activateHandler = (searchContext, rootElement) => { - (provider.settingsEditor as PlayerSettingsEditor)?.SetSectionOpenListener(provider.Repaint); + (provider.settingsEditor as PlayerSettingsEditor)?.SetValueChangeListeners(provider.Repaint); }; return provider; } diff --git a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsSplashScreenEditor.cs b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsSplashScreenEditor.cs index 0e4130b7d1..65519def18 100644 --- a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsSplashScreenEditor.cs +++ b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsSplashScreenEditor.cs @@ -77,7 +77,7 @@ class Texts { public GUIContent animate = EditorGUIUtility.TrTextContent("Animation"); public GUIContent backgroundColor = EditorGUIUtility.TrTextContent("Background Color", "Background color when no background image is used."); - public GUIContent backgroundImage = EditorGUIUtility.TrTextContent("Background Image", "Image to be used in landscape and portrait(when portrait image is not set)."); + public GUIContent backgroundImage = EditorGUIUtility.TrTextContent("Background Image", "Image to be used in landscape and portrait (when portrait image is not set)."); public GUIContent backgroundPortraitImage = EditorGUIUtility.TrTextContent("Alternate Portrait Image*", "Optional image to be used in portrait mode."); public GUIContent backgroundTitle = EditorGUIUtility.TrTextContent("Background*"); public GUIContent backgroundZoom = EditorGUIUtility.TrTextContent("Background Zoom"); @@ -200,12 +200,14 @@ private void DrawLogoListElementCallback(Rect rect, int index, bool isActive, bo logo.objectReferenceValue = value; // Properties - EditorGUIUtility.labelWidth = k_LogoListPropertyLabelWidth; var propertyRect = new Rect(rect.x + unityLogoWidth, rect.y + EditorGUIUtility.standardVerticalSpacing, rect.width - unityLogoWidth, EditorGUIUtility.singleLineHeight); var duration = element.FindPropertyRelative("duration"); EditorGUI.BeginChangeCheck(); + var oldLabelWidth = EditorGUIUtility.labelWidth; + EditorGUIUtility.labelWidth = k_LogoListPropertyLabelWidth; var newDurationVal = EditorGUI.Slider(propertyRect, k_Texts.logoDuration, duration.floatValue, k_MinLogoTime, k_MaxLogoTime); + EditorGUIUtility.labelWidth = oldLabelWidth; if (EditorGUI.EndChangeCheck()) duration.floatValue = newDurationVal; diff --git a/Editor/Mono/Inspector/PreviewRenderUtility.cs b/Editor/Mono/Inspector/PreviewRenderUtility.cs index 9545751984..635eb4656f 100644 --- a/Editor/Mono/Inspector/PreviewRenderUtility.cs +++ b/Editor/Mono/Inspector/PreviewRenderUtility.cs @@ -221,7 +221,7 @@ public void BeginPreview(Rect r, GUIStyle previewBackground) { Texture defaultEnvTexture = ReflectionProbe.defaultTexture; - if (Unsupported.SetOverrideRenderSettings(previewScene.scene)) + if (Unsupported.SetOverrideLightingSettings(previewScene.scene)) { RenderSettings.ambientMode = AmbientMode.Flat; RenderSettings.ambientLight = ambientColor; @@ -260,7 +260,7 @@ public void BeginStaticPreview(Rect r) { var oldProbe = RenderSettings.ambientProbe; Texture defaultEnvTexture = ReflectionProbe.defaultTexture; - if (Unsupported.SetOverrideRenderSettings(previewScene.scene)) + if (Unsupported.SetOverrideLightingSettings(previewScene.scene)) { // Most preview windows just want the light probe from the main scene so by default we copy it here. It can then be overridden if user wants. RenderSettings.ambientProbe = oldProbe; @@ -338,7 +338,7 @@ public void BeginPreviewHDR(Rect r, GUIStyle previewBackground) public Texture EndPreview() { - Unsupported.RestoreOverrideRenderSettings(); + Unsupported.RestoreOverrideLightingSettings(); m_SavedState.Restore(); FinishFrame(); @@ -347,7 +347,7 @@ public Texture EndPreview() private void FinishFrame() { - Unsupported.RestoreOverrideRenderSettings(); + Unsupported.RestoreOverrideLightingSettings(); foreach (var light in lights) light.enabled = false; } @@ -366,7 +366,7 @@ internal static void DrawPreview(Rect r, Texture texture) public Texture2D EndStaticPreview() { if (!EditorApplication.isUpdating) - Unsupported.RestoreOverrideRenderSettings(); + Unsupported.RestoreOverrideLightingSettings(); var tmp = RenderTexture.GetTemporary((int)m_TargetRect.width, (int)m_TargetRect.height, 0, GraphicsFormat.R8G8B8A8_UNorm); diff --git a/Editor/Mono/Inspector/QualitySettingsEditor.cs b/Editor/Mono/Inspector/QualitySettingsEditor.cs index a233b16d0f..ceda524753 100644 --- a/Editor/Mono/Inspector/QualitySettingsEditor.cs +++ b/Editor/Mono/Inspector/QualitySettingsEditor.cs @@ -21,7 +21,7 @@ private class Content public static readonly GUIContent kStreamingMipmapsActive = EditorGUIUtility.TrTextContent("Texture Streaming", "Enable to use texture mipmap streaming."); public static readonly GUIContent kStreamingMipmapsMemoryBudget = EditorGUIUtility.TrTextContent("Memory Budget", "Texture Streaming Budget in MB."); public static readonly GUIContent kStreamingMipmapsRenderersPerFrame = EditorGUIUtility.TrTextContent("Renderers Per Frame", "Number of renderers to process each frame. A lower number will decrease the CPU load at the cost of delaying the mipmap loading."); - public static readonly GUIContent kStreamingMipmapsAddAllCameras = EditorGUIUtility.TrTextContent("Add All Cameras", "Adds all cameras to texture streaming system even if it lacks a StreamingController component. If a camera has the StreamingController component that will control whether its processed or not."); + public static readonly GUIContent kStreamingMipmapsAddAllCameras = EditorGUIUtility.TrTextContent("Add All Cameras", "Adds all cameras to texture streaming system even if it lacks a StreamingController component. If a camera has the StreamingController component, that will control whether it is processed or not."); public static readonly GUIContent kStreamingMipmapsMaxLevelReduction = EditorGUIUtility.TrTextContent("Max Level Reduction", "This is the maximum number of mipmap levels a texture should drop."); public static readonly GUIContent kStreamingMipmapsMaxFileIORequests = EditorGUIUtility.TrTextContent("Max IO Requests", "Maximum number of texture file IO calls active from the texture streaming system at any time."); diff --git a/Editor/Mono/Inspector/RectTransformEditor.cs b/Editor/Mono/Inspector/RectTransformEditor.cs index 95cb889406..dc117a14cb 100644 --- a/Editor/Mono/Inspector/RectTransformEditor.cs +++ b/Editor/Mono/Inspector/RectTransformEditor.cs @@ -41,7 +41,7 @@ class Styles public GUIContent anchorsContent = EditorGUIUtility.TrTextContent("Anchors"); public GUIContent anchorMinContent = EditorGUIUtility.TrTextContent("Min", "The normalized position in the parent rectangle that the lower left corner is anchored to."); public GUIContent anchorMaxContent = EditorGUIUtility.TrTextContent("Max", "The normalized position in the parent rectangle that the upper right corner is anchored to."); - public GUIContent pivotContent = EditorGUIUtility.TrTextContent("Pivot", "The pivot point specified in normalized values between 0 and 1. The pivot point is the origin of this rectangle. Rotation and scaling is around this point."); + public GUIContent pivotContent = EditorGUIUtility.TrTextContent("Pivot", "The pivot point specified in normalized values between 0 and 1. The pivot point is the origin of this rectangle. Rotation and scaling are around this point."); public GUIContent transformScaleContent = EditorGUIUtility.TrTextContent("Scale", "The local scaling of this Game Object relative to the parent. This scales everything including image borders and text."); public GUIContent rawEditContent; public GUIContent blueprintContent; diff --git a/Editor/Mono/Inspector/ReflectionProbeEditor.cs b/Editor/Mono/Inspector/ReflectionProbeEditor.cs index c9563ffd04..a36d13a86d 100644 --- a/Editor/Mono/Inspector/ReflectionProbeEditor.cs +++ b/Editor/Mono/Inspector/ReflectionProbeEditor.cs @@ -108,7 +108,7 @@ static Styles() public static GUIContent timeSlicing = EditorGUIUtility.TrTextContent("Time Slicing", "If enabled this probe will update over several frames, to help reduce the impact on the frame rate"); public static GUIContent refreshMode = EditorGUIUtility.TrTextContent("Refresh Mode", "Controls how this probe refreshes in the Player"); - public static GUIContent typeText = EditorGUIUtility.TrTextContent("Type", "'Baked Cubemap' uses the 'Auto Baking' mode from the Lighting window. If it is enabled then baking is automatic otherwise manual bake is needed (use the bake button below). \n'Custom' can be used if a custom cubemap is wanted. \n'Realtime' can be used to dynamically re-render the cubemap during runtime (via scripting)."); + public static GUIContent typeText = EditorGUIUtility.TrTextContent("Type", "'Baked Cubemap' uses the 'Auto Baking' mode from the Lighting window. If it is enabled, then baking is automatic otherwise manual bake is needed (use the bake button below). \n'Custom' can be used if a custom cubemap is wanted. \n'Realtime' can be used to dynamically re-render the cubemap during runtime (via scripting)."); public static GUIContent[] reflectionProbeMode = { EditorGUIUtility.TrTextContent("Baked"), EditorGUIUtility.TrTextContent("Custom"), EditorGUIUtility.TrTextContent("Realtime") }; public static int[] reflectionProbeModeValues = { (int)ReflectionProbeMode.Baked, (int)ReflectionProbeMode.Custom, (int)ReflectionProbeMode.Realtime }; diff --git a/Editor/Mono/Inspector/RenderTextureEditor.cs b/Editor/Mono/Inspector/RenderTextureEditor.cs index 08827238c4..66b84d5869 100644 --- a/Editor/Mono/Inspector/RenderTextureEditor.cs +++ b/Editor/Mono/Inspector/RenderTextureEditor.cs @@ -16,14 +16,14 @@ private class Styles { public readonly GUIContent size = EditorGUIUtility.TrTextContent("Size", "Size of the render texture in pixels."); public readonly GUIContent cross = EditorGUIUtility.TextContent("x"); - public readonly GUIContent antiAliasing = EditorGUIUtility.TrTextContent("Anti-Aliasing", "Number of anti-aliasing samples."); + public readonly GUIContent antiAliasing = EditorGUIUtility.TrTextContent("Anti-aliasing", "Number of anti-aliasing samples."); public readonly GUIContent colorFormat = EditorGUIUtility.TrTextContent("Color Format", "Format of the color buffer."); public readonly GUIContent depthBuffer = EditorGUIUtility.TrTextContent("Depth Buffer", "Format of the depth buffer."); public readonly GUIContent enableCompatibleFormat = EditorGUIUtility.TrTextContent("Enable Compatible Color Format", "Lets the color format be changed to compatible and supported formats for the target platform automatically, if the target platform doesn't support the input format."); public readonly GUIContent dimension = EditorGUIUtility.TrTextContent("Dimension", "Is the texture 2D, Cube or 3D?"); public readonly GUIContent enableMipmaps = EditorGUIUtility.TrTextContent("Enable Mip Maps", "This render texture will have Mip Maps."); public readonly GUIContent bindMS = EditorGUIUtility.TrTextContent("Bind multisampled", "If enabled, the texture will not go through an AA resolve if bound to a shader."); - public readonly GUIContent autoGeneratesMipmaps = EditorGUIUtility.TrTextContent("Auto generate Mip Maps", "This render texture automatically generate its Mip Maps."); + public readonly GUIContent autoGeneratesMipmaps = EditorGUIUtility.TrTextContent("Auto generate Mip Maps", "This render texture automatically generates its Mip Maps."); public readonly GUIContent sRGBTexture = EditorGUIUtility.TrTextContent("sRGB (Color RenderTexture)", "RenderTexture content is stored in gamma space. Non-HDR color textures should enable this flag."); public readonly GUIContent useDynamicScale = EditorGUIUtility.TrTextContent("Dynamic Scaling", "Allow the texture to be automatically resized by ScalableBufferManager, to support dynamic resolution."); diff --git a/Editor/Mono/Inspector/Rigidbody2DEditor.cs b/Editor/Mono/Inspector/Rigidbody2DEditor.cs index 92227aed1d..cb8a3ea680 100644 --- a/Editor/Mono/Inspector/Rigidbody2DEditor.cs +++ b/Editor/Mono/Inspector/Rigidbody2DEditor.cs @@ -157,10 +157,6 @@ public override void OnInspectorGUI() ToggleFreezeRotation(constraints, m_FreezeRotationLabel, 2); EditorGUI.indentLevel--; } - - // Provide end-user warning about the equivalence of all constraints on versus no Rigidbody2D component. - if (constraints == RigidbodyConstraints2D.FreezeAll) - EditorGUILayout.HelpBox("Rather than turning on all constraints, you may want to consider removing the Rigidbody2D component which makes any colliders static. This gives far better performance overall.", MessageType.Info); } EditorGUILayout.EndFadeGroup(); } diff --git a/Editor/Mono/Inspector/ScriptExecutionOrderInspector.cs b/Editor/Mono/Inspector/ScriptExecutionOrderInspector.cs index e46cb66d38..fee0b38a94 100644 --- a/Editor/Mono/Inspector/ScriptExecutionOrderInspector.cs +++ b/Editor/Mono/Inspector/ScriptExecutionOrderInspector.cs @@ -274,9 +274,22 @@ private void Apply() if (Provider.enabled) { - var task = Provider.Checkout(changedScripts.ToArray(), CheckoutMode.Meta); - task.Wait(); - editable = task.success; + var needToCheckout = new AssetList(); + foreach (var s in changedScripts) + { + var asset = Provider.GetAssetByPath(AssetDatabase.GetAssetPath(s)); + if (asset == null) // script might be outside of the project (e.g. in a package) + continue; + if (AssetDatabase.IsMetaFileOpenForEdit(s, StatusQueryOptions.UseCachedIfPossible)) + continue; // might not need a checkout (not connected, etc.) + needToCheckout.Add(asset); + } + if (needToCheckout.Any()) + { + var task = Provider.Checkout(needToCheckout, CheckoutMode.Meta); + task.Wait(); + editable = task.success; + } } if (editable) diff --git a/Editor/Mono/Inspector/ShaderGUI.cs b/Editor/Mono/Inspector/ShaderGUI.cs index a48ba6cbb5..4dd559d3c1 100644 --- a/Editor/Mono/Inspector/ShaderGUI.cs +++ b/Editor/Mono/Inspector/ShaderGUI.cs @@ -61,22 +61,18 @@ internal static class ShaderGUIUtility { private static Type ExtractCustomEditorType(string customEditorName) { - if (string.IsNullOrEmpty(customEditorName)) return null; + if (string.IsNullOrEmpty(customEditorName)) + return null; // To allow users to implement their own ShaderGUI for the Standard shader we iterate in reverse order // because the UnityEditor assembly is assumed first in the assembly list. // Users can now place a copy of the StandardShaderGUI script in the project and start modifying that copy to make their own version. - - string unityEditorFullName = "UnityEditor." + customEditorName; // for convenience: adding UnityEditor namespace is not needed in the shader - - var editorAssemblies = EditorAssemblies.loadedAssemblies; - for (int i = editorAssemblies.Length - 1; i >= 0; i--) + var unityEditorFullName = $"UnityEditor.{customEditorName}"; // for convenience: adding UnityEditor namespace is not needed in the shader + foreach (var type in TypeCache.GetTypesDerivedFrom()) { - foreach (var type in AssemblyHelper.GetTypesFromAssembly(editorAssemblies[i])) - { - if (type.FullName.Equals(customEditorName, StringComparison.Ordinal) || type.FullName.Equals(unityEditorFullName, StringComparison.Ordinal)) - return typeof(ShaderGUI).IsAssignableFrom(type) ? type : null; - } + if (type.FullName.Equals(customEditorName, StringComparison.Ordinal) || + type.FullName.Equals(unityEditorFullName, StringComparison.Ordinal)) + return typeof(ShaderGUI).IsAssignableFrom(type) ? type : null; } return null; } diff --git a/Editor/Mono/Inspector/ShaderInspector.cs b/Editor/Mono/Inspector/ShaderInspector.cs index 4052cf80d6..153317b9ed 100644 --- a/Editor/Mono/Inspector/ShaderInspector.cs +++ b/Editor/Mono/Inspector/ShaderInspector.cs @@ -59,6 +59,19 @@ internal class Styles static readonly int kErrorViewHash = "ShaderErrorView".GetHashCode(); Vector2 m_ScrollPosition = Vector2.zero; + private Material m_SrpCompatibilityCheckMaterial = null; + + public Material srpCompatibilityCheckMaterial + { + get + { + if (m_SrpCompatibilityCheckMaterial == null) + { + m_SrpCompatibilityCheckMaterial = new Material(target as Shader); + } + return m_SrpCompatibilityCheckMaterial; + } + } public virtual void OnEnable() { @@ -66,6 +79,14 @@ public virtual void OnEnable() ShaderUtil.FetchCachedErrors(s); } + public virtual void OnDisable() + { + if (m_SrpCompatibilityCheckMaterial != null) + { + GameObject.DestroyImmediate(m_SrpCompatibilityCheckMaterial); + } + } + private static string GetPropertyType(Shader s, int index) { ShaderUtil.ShaderPropertyType type = ShaderUtil.GetPropertyType(s, index); @@ -116,8 +137,8 @@ public override void OnInspectorGUI() // If any SRP is active, then display the SRP Batcher compatibility status if (RenderPipelineManager.currentPipeline != null) { - var mat = new Material(s); - mat.SetPass(0); // NOTE: Force the shader compilation to ensure GetSRPBatcherCompatibilityCode will be up to date + // NOTE: Force the shader compilation to ensure GetSRPBatcherCompatibilityCode will be up to date + srpCompatibilityCheckMaterial.SetPass(0); int subShader = ShaderUtil.GetShaderActiveSubshaderIndex(s); int SRPErrCode = ShaderUtil.GetSRPBatcherCompatibilityCode(s, subShader); string result = (0 == SRPErrCode) ? "compatible" : "not compatible"; @@ -127,6 +148,7 @@ public override void OnInspectorGUI() EditorGUILayout.HelpBox(ShaderUtil.GetSRPBatcherCompatibilityIssueReason(s, subShader, SRPErrCode), MessageType.Info); } } + ShowShaderProperties(s); } } diff --git a/Editor/Mono/Inspector/SortingGroupEditor.cs b/Editor/Mono/Inspector/SortingGroupEditor.cs index abb39e0716..2f08dfd8c8 100644 --- a/Editor/Mono/Inspector/SortingGroupEditor.cs +++ b/Editor/Mono/Inspector/SortingGroupEditor.cs @@ -17,6 +17,7 @@ internal class SortingGroupEditor : Editor public virtual void OnEnable() { + alwaysAllowExpansion = true; m_SortingOrder = serializedObject.FindProperty("m_SortingOrder"); m_SortingLayerID = serializedObject.FindProperty("m_SortingLayerID"); } diff --git a/Editor/Mono/Inspector/SortingLayerEditorUtility.cs b/Editor/Mono/Inspector/SortingLayerEditorUtility.cs index 079b0dd800..82777af4b6 100644 --- a/Editor/Mono/Inspector/SortingLayerEditorUtility.cs +++ b/Editor/Mono/Inspector/SortingLayerEditorUtility.cs @@ -12,19 +12,41 @@ internal class SortingLayerEditorUtility { private static class Styles { + private static GUIStyle m_BoldPopupStyle; + public static GUIContent m_SortingLayerStyle = EditorGUIUtility.TrTextContent("Sorting Layer", "Name of the Renderer's sorting layer"); public static GUIContent m_SortingOrderStyle = EditorGUIUtility.TrTextContent("Order in Layer", "Renderer's order within a sorting layer"); + + public static GUIStyle boldPopupStyle + { + get + { + if (m_BoldPopupStyle == null) + { + m_BoldPopupStyle = new GUIStyle(EditorStyles.popup); + m_BoldPopupStyle.fontStyle = FontStyle.Bold; + } + return m_BoldPopupStyle; + } + } + } + + internal static bool HasPrefabOverride(SerializedProperty property) + { + return property != null && property.serializedObject.targetObjectsCount == 1 && property.isInstantiatedPrefab && property.prefabOverride; } public static void RenderSortingLayerFields(SerializedProperty sortingOrder, SerializedProperty sortingLayer) { - EditorGUILayout.SortingLayerField(Styles.m_SortingLayerStyle, sortingLayer, EditorStyles.popup, EditorStyles.label); + var hasPrefabOverride = HasPrefabOverride(sortingLayer); + EditorGUILayout.SortingLayerField(Styles.m_SortingLayerStyle, sortingLayer, hasPrefabOverride ? Styles.boldPopupStyle : EditorStyles.popup, hasPrefabOverride ? EditorStyles.boldLabel : EditorStyles.label); EditorGUILayout.PropertyField(sortingOrder, Styles.m_SortingOrderStyle); } public static void RenderSortingLayerFields(Rect r, SerializedProperty sortingOrder, SerializedProperty sortingLayer) { - EditorGUI.SortingLayerField(r, Styles.m_SortingLayerStyle, sortingLayer, EditorStyles.popup, EditorStyles.label); + var hasPrefabOverride = HasPrefabOverride(sortingLayer); + EditorGUI.SortingLayerField(r, Styles.m_SortingLayerStyle, sortingLayer, hasPrefabOverride ? Styles.boldPopupStyle : EditorStyles.popup, hasPrefabOverride ? EditorStyles.boldLabel : EditorStyles.label); r.y += EditorGUIUtility.singleLineHeight; EditorGUI.PropertyField(r, sortingOrder, Styles.m_SortingOrderStyle); } diff --git a/Editor/Mono/Inspector/SpriteRendererEditor.cs b/Editor/Mono/Inspector/SpriteRendererEditor.cs index a6afd7e753..9f2f9a9504 100644 --- a/Editor/Mono/Inspector/SpriteRendererEditor.cs +++ b/Editor/Mono/Inspector/SpriteRendererEditor.cs @@ -24,7 +24,7 @@ class Styles public static readonly GUIContent flipYLabel = EditorGUIUtility.TrTextContent("Y", "Sprite vertical flipping"); public static readonly int flipToggleHash = "FlipToggleHash".GetHashCode(); - public static readonly GUIContent fullTileLabel = EditorGUIUtility.TrTextContent("Tile Mode", "Specify the 9 slice tiling behaviour"); + public static readonly GUIContent fullTileLabel = EditorGUIUtility.TrTextContent("Tile Mode", "Specify the 9-slice tiling behaviour"); public static readonly GUIContent fullTileThresholdLabel = EditorGUIUtility.TrTextContent("Stretch Value", "This value defines how much the center portion will stretch before it tiles."); public static readonly GUIContent drawModeLabel = EditorGUIUtility.TrTextContent("Draw Mode", "Specify the draw mode for the sprite"); public static readonly GUIContent widthLabel = EditorGUIUtility.TrTextContent("Width", "The width dimension value for the sprite"); @@ -87,59 +87,50 @@ public override void OnInspectorGUI() FlipToggles(); - EditorGUILayout.PropertyField(m_DrawMode, Styles.drawModeLabel); - - m_ShowDrawMode.target = ShouldShowDrawMode(); - if (EditorGUILayout.BeginFadeGroup(m_ShowDrawMode.faded)) + using (new EditorGUI.DisabledGroupScope(IsTextureless())) { - string notFullRectWarning = GetSpriteNotFullRectWarning(); - if (notFullRectWarning != null) - EditorGUILayout.HelpBox(notFullRectWarning, MessageType.Warning); - - EditorGUI.indentLevel++; - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.PrefixLabel(Styles.sizeLabel); - EditorGUI.showMixedValue = m_Size.hasMultipleDifferentValues; - FloatFieldLabelAbove(Styles.widthLabel, m_Size.FindPropertyRelative("x")); - FloatFieldLabelAbove(Styles.heightLabel, m_Size.FindPropertyRelative("y")); - EditorGUI.showMixedValue = false; - EditorGUILayout.EndHorizontal(); - - m_ShowTileMode.target = ShouldShowTileMode(); - if (EditorGUILayout.BeginFadeGroup(m_ShowTileMode.faded)) + EditorGUILayout.PropertyField(m_DrawMode, Styles.drawModeLabel); + m_ShowDrawMode.target = ShouldShowDrawMode(); + if (EditorGUILayout.BeginFadeGroup(m_ShowDrawMode.faded)) { - EditorGUILayout.PropertyField(m_SpriteTileMode, Styles.fullTileLabel); - - m_ShowAdaptiveThreshold.target = ShouldShowAdaptiveThreshold(); - if (EditorGUILayout.BeginFadeGroup(m_ShowAdaptiveThreshold.faded)) + string notFullRectWarning = GetSpriteNotFullRectWarning(); + if (notFullRectWarning != null) + EditorGUILayout.HelpBox(notFullRectWarning, MessageType.Warning); + + EditorGUI.indentLevel++; + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PrefixLabel(Styles.sizeLabel); + EditorGUI.showMixedValue = m_Size.hasMultipleDifferentValues; + FloatFieldLabelAbove(Styles.widthLabel, m_Size.FindPropertyRelative("x")); + FloatFieldLabelAbove(Styles.heightLabel, m_Size.FindPropertyRelative("y")); + EditorGUI.showMixedValue = false; + EditorGUILayout.EndHorizontal(); + + + m_ShowTileMode.target = ShouldShowTileMode(); + if (EditorGUILayout.BeginFadeGroup(m_ShowTileMode.faded)) { - EditorGUI.indentLevel++; - EditorGUILayout.Slider(m_AdaptiveModeThreshold, 0.0f, 1.0f, Styles.fullTileThresholdLabel); - EditorGUI.indentLevel--; + EditorGUILayout.PropertyField(m_SpriteTileMode, Styles.fullTileLabel); + + m_ShowAdaptiveThreshold.target = ShouldShowAdaptiveThreshold(); + if (EditorGUILayout.BeginFadeGroup(m_ShowAdaptiveThreshold.faded)) + { + EditorGUI.indentLevel++; + EditorGUILayout.Slider(m_AdaptiveModeThreshold, 0.0f, 1.0f, Styles.fullTileThresholdLabel); + EditorGUI.indentLevel--; + } + EditorGUILayout.EndFadeGroup(); } EditorGUILayout.EndFadeGroup(); + + EditorGUI.indentLevel--; } EditorGUILayout.EndFadeGroup(); - EditorGUI.indentLevel--; } - EditorGUILayout.EndFadeGroup(); EditorGUILayout.PropertyField(m_MaskInteraction, Styles.maskInteractionLabel); EditorGUILayout.PropertyField(m_SpriteSortPoint, Styles.spriteSortPointLabel); - - // material - Rect r = GUILayoutUtility.GetRect( - EditorGUILayout.kLabelFloatMinW, EditorGUILayout.kLabelFloatMaxW, - EditorGUI.kSingleLineHeight, EditorGUI.kSingleLineHeight); - - EditorGUI.showMixedValue = m_Material.hasMultipleDifferentValues; - Object currentMaterialRef = m_Material.GetArrayElementAtIndex(0).objectReferenceValue; - Object returnedMaterialRef = EditorGUI.ObjectField(r, Styles.materialLabel, currentMaterialRef, typeof(Material), false); - if (returnedMaterialRef != currentMaterialRef) - { - m_Material.GetArrayElementAtIndex(0).objectReferenceValue = returnedMaterialRef; - } - EditorGUI.showMixedValue = false; + EditorGUILayout.PropertyField(m_Material.GetArrayElementAtIndex(0), Styles.materialLabel, true); ShowMaterialError(); @@ -174,6 +165,17 @@ string GetSpriteNotFullRectWarning() return null; } + bool IsTextureless() + { + foreach (var t in targets) + { + var sr = (t as SpriteRenderer); + if (sr.sprite != null && sr.sprite.texture == null) + return true; + } + return false; + } + bool ShouldShowDrawMode() { return m_DrawMode.intValue != (int)SpriteDrawMode.Simple && !m_DrawMode.hasMultipleDifferentValues; diff --git a/Editor/Mono/Inspector/StandardParticlesShaderGUI.cs b/Editor/Mono/Inspector/StandardParticlesShaderGUI.cs index 6b9f103e66..8166da07ce 100644 --- a/Editor/Mono/Inspector/StandardParticlesShaderGUI.cs +++ b/Editor/Mono/Inspector/StandardParticlesShaderGUI.cs @@ -484,7 +484,7 @@ void DoVertexStreamsArea(Material material) bool useGPUInstancing = ShaderUtil.HasProceduralInstancing(material.shader); if (useGPUInstancing && m_RenderersUsingThisMaterial.Count > 0) { - if (!m_RenderersUsingThisMaterial[0].enableGPUInstancing) + if (!m_RenderersUsingThisMaterial[0].enableGPUInstancing || m_RenderersUsingThisMaterial[0].renderMode != ParticleSystemRenderMode.Mesh) useGPUInstancing = false; } @@ -790,9 +790,13 @@ void CacheRenderersUsingThisMaterial(Material material) { m_RenderersUsingThisMaterial.Clear(); - ParticleSystemRenderer[] renderers = UnityEngine.Object.FindObjectsOfType(typeof(ParticleSystemRenderer)) as ParticleSystemRenderer[]; + ParticleSystemRenderer[] renderers = Resources.FindObjectsOfTypeAll(typeof(ParticleSystemRenderer)) as ParticleSystemRenderer[]; foreach (ParticleSystemRenderer renderer in renderers) { + var go = renderer.gameObject; + if (go.hideFlags == HideFlags.NotEditable || go.hideFlags == HideFlags.HideAndDontSave) + continue; + if (renderer.sharedMaterial == material) m_RenderersUsingThisMaterial.Add(renderer); } diff --git a/Editor/Mono/Inspector/TimeManagerInspector.cs b/Editor/Mono/Inspector/TimeManagerInspector.cs index 4d7aa39df1..a125354939 100644 --- a/Editor/Mono/Inspector/TimeManagerInspector.cs +++ b/Editor/Mono/Inspector/TimeManagerInspector.cs @@ -12,7 +12,7 @@ internal class TimeManagerEditor : Editor class Content { public static readonly GUIContent fixedTimestepLabel = EditorGUIUtility.TrTextContent("Fixed Timestep", "A framerate-independent interval that dictates when physics calculations and FixedUpdate() events are performed."); - public static readonly GUIContent maxAllowedTimestepLabel = EditorGUIUtility.TrTextContent("Maximum Allowed Timestep", "A framerate-independent interval that caps the worst case scenario when framerate is low. Physics calculations and FixedUpdate() events will not be performed for longer time than specified."); + public static readonly GUIContent maxAllowedTimestepLabel = EditorGUIUtility.TrTextContent("Maximum Allowed Timestep", "A framerate-independent interval that caps the worst-case scenario when framerate is low. Physics calculations and FixedUpdate() events will not be performed for longer time than specified."); public static readonly GUIContent timeScaleLabel = EditorGUIUtility.TrTextContent("Time Scale", "The speed at which time progresses. Change this value to simulate bullet-time effects. A value of 1 means real-time. A value of .5 means half speed; a value of 2 is double speed."); public static readonly GUIContent maxParticleTimestepLabel = EditorGUIUtility.TrTextContent("Maximum Particle Timestep", "The maximum time that should be allowed to process particles for a frame."); } diff --git a/Editor/Mono/Inspector/UnityEventDrawer.cs b/Editor/Mono/Inspector/UnityEventDrawer.cs index baef947eb9..976ae2c1a9 100644 --- a/Editor/Mono/Inspector/UnityEventDrawer.cs +++ b/Editor/Mono/Inspector/UnityEventDrawer.cs @@ -384,12 +384,55 @@ protected virtual void OnReorderEvent(ReorderableList list) static UnityEventBase GetDummyEvent(SerializedProperty prop) { - // Create dummy instance of this type... we need it for function validation ect - var typeName = prop.FindPropertyRelative("m_TypeName").stringValue; - Type type = Type.GetType(typeName, false); - if (type == null) + //Use the SerializedProperty path to iterate through the fields of the inspected targetObject + Object tgtobj = prop.serializedObject.targetObject; + if (tgtobj == null) return new UnityEvent(); - return Activator.CreateInstance(type) as UnityEventBase; + + UnityEventBase ret = null; + Type ft = tgtobj.GetType(); + var bindflags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; + do + { + ret = GetDummyEventHelper(prop.propertyPath, ft, bindflags); + //no need to look for public members again since the base type covered that + bindflags = BindingFlags.Instance | BindingFlags.NonPublic; + ft = ft.BaseType; + } + while (ret == null && ft != null); + // go up the class hierarchy if it exists and the property is not found on the child + return (ret == null) ? new UnityEvent() : ret; + } + + private static UnityEventBase GetDummyEventHelper(string propPath, Type targetObjectType, BindingFlags flags) + { + while (propPath.Length != 0) + { + //we could have a leftover '.' if the previous iteration handled an array element + if (propPath.StartsWith(".")) + propPath = propPath.Substring(1); + + var splits = propPath.Split(new[] { '.' }, 2); + var newField = targetObjectType.GetField(splits[0], flags); + if (newField == null) + break; + + targetObjectType = newField.FieldType; + if (targetObjectType.IsArrayOrList()) + targetObjectType = targetObjectType.GetArrayOrListElementType(); + + //the last item in the property path could have been an array element + //bail early in that case + if (splits.Length == 1) + break; + + propPath = splits[1]; + if (propPath.StartsWith("Array.data[")) + propPath = propPath.Split(new[] { ']' }, 2)[1]; + } + if (targetObjectType.IsSubclassOf(typeof(UnityEventBase))) + return Activator.CreateInstance(targetObjectType) as UnityEventBase; + return null; } struct ValidMethodMap diff --git a/Editor/Mono/InternalEditorUtility.bindings.cs b/Editor/Mono/InternalEditorUtility.bindings.cs index 07bc66aabf..387c759ba9 100644 --- a/Editor/Mono/InternalEditorUtility.bindings.cs +++ b/Editor/Mono/InternalEditorUtility.bindings.cs @@ -10,6 +10,7 @@ using UnityEngine.Bindings; using UnityEditor.Scripting.ScriptCompilation; using System.Globalization; +using Unity.CodeEditor; using TargetAttributes = UnityEditor.BuildTargetDiscovery.TargetAttributes; namespace UnityEditorInternal @@ -128,6 +129,10 @@ public extern static bool inBatchMode [NativeMethod("PerformUnmarkedBumpMapTexturesFixingAfterDialog")] public extern static void BumpMapSettingsFixingWindowReportResult(int result); + [StaticAccessor("BumpMapSettings::Get()", StaticAccessorType.Dot)] + [NativeMethod("PerformUnmarkedBumpMapTexturesFixing")] + public extern static bool PerformUnmarkedBumpMapTexturesFixing(); + [FreeFunction("InternalEditorUtilityBindings::BumpMapTextureNeedsFixingInternal")] public extern static bool BumpMapTextureNeedsFixingInternal(Material material, string propName, bool flaggedAsNormal); @@ -632,8 +637,13 @@ public static void SetCustomLighting(Light[] lights, Color ambient) [StaticAccessor("GetRenderManager()", StaticAccessorType.Dot)] extern public static bool HasFullscreenCamera(); + public static Bounds CalculateSelectionBounds(bool usePivotOnlyForParticles, bool onlyUseActiveSelection) + { + return CalculateSelectionBounds(usePivotOnlyForParticles, onlyUseActiveSelection, false); + } + [FreeFunction] - extern public static Bounds CalculateSelectionBounds(bool usePivotOnlyForParticles, bool onlyUseActiveSelection); + extern public static Bounds CalculateSelectionBounds(bool usePivotOnlyForParticles, bool onlyUseActiveSelection, bool ignoreEditableField); internal static Bounds CalculateSelectionBoundsInSpace(Vector3 position, Quaternion rotation, bool rectBlueprintMode) { @@ -733,7 +743,11 @@ private static Bounds GetLocalBounds(GameObject gameObject) public static bool OpenFileAtLineExternal(string filename, int line) { - return OpenFileAtLineExternal(filename, line, 0); + if (!CodeEditor.Editor.Current.OpenProject(filename, line)) + { + return OpenFileAtLineExternal(filename, line, 0); + } + return true; } [FreeFunction("AssetDatabaseDeprecated::CanConnectToCacheServer")] diff --git a/Editor/Mono/Media/Bindings/MediaDecoder.bindings.cs b/Editor/Mono/Media/Bindings/MediaDecoder.bindings.cs index 85bb8aa548..5fa67e8172 100644 --- a/Editor/Mono/Media/Bindings/MediaDecoder.bindings.cs +++ b/Editor/Mono/Media/Bindings/MediaDecoder.bindings.cs @@ -7,6 +7,7 @@ using UnityEngine; using UnityEngine.Bindings; using UnityEngine.Scripting; +using UnityEngine.Video; using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("VideoTesting")] @@ -21,6 +22,11 @@ public MediaDecoder(string filePath) m_Ptr = Create(filePath); } + public MediaDecoder(VideoClip clip) + { + m_Ptr = Create(clip); + } + ~MediaDecoder() { Dispose(); @@ -55,10 +61,23 @@ private IntPtr Create(string filePath) return ptr; } + private IntPtr Create(VideoClip clip) + { + IntPtr ptr = Internal_MediaDecoder_CreateFromClip(clip); + if (ptr == IntPtr.Zero) + throw new InvalidOperationException( + "MediaDecoder: Could not open clip " + clip.name); + return ptr; + } + [NativeHeader("Editor/Mono/Media/Bindings/MediaDecoder.bindings.h")] [FreeFunction] extern private static IntPtr Internal_MediaDecoder_Create(string filePath); + [NativeHeader("Editor/Mono/Media/Bindings/MediaDecoder.bindings.h")] + [FreeFunction] + extern private static IntPtr Internal_MediaDecoder_CreateFromClip(VideoClip clip); + [NativeHeader("Modules/Video/Public/Base/VideoClipMedia.h")] [FreeFunction("VideoClipMedia::Release")] extern private static void Internal_Release(IntPtr decoder); diff --git a/Editor/Mono/Modules/DefaultCompilationExtension.cs b/Editor/Mono/Modules/DefaultCompilationExtension.cs index b4ac96d048..2a0ed8ef0a 100644 --- a/Editor/Mono/Modules/DefaultCompilationExtension.cs +++ b/Editor/Mono/Modules/DefaultCompilationExtension.cs @@ -25,11 +25,6 @@ public virtual string[] GetCompilerExtraAssemblyPaths(bool isEditor, string asse return new string[] {}; } - public virtual IAssemblyResolver GetAssemblyResolver(bool buildingForEditor, string assemblyPath, string[] searchDirectories) - { - return null; - } - public virtual IEnumerable GetWindowsMetadataReferences() { return new string[0]; diff --git a/Editor/Mono/Modules/PlatformSupportModule.cs b/Editor/Mono/Modules/PlatformSupportModule.cs index 0c2a77f235..fc7a89b043 100644 --- a/Editor/Mono/Modules/PlatformSupportModule.cs +++ b/Editor/Mono/Modules/PlatformSupportModule.cs @@ -409,7 +409,6 @@ internal interface ICompilationExtension { CSharpCompiler GetCsCompiler(bool buildingForEditor, ScriptAssembly scriptAssembly); string[] GetCompilerExtraAssemblyPaths(bool isEditor, string assemblyPathName); - IAssemblyResolver GetAssemblyResolver(bool buildingForEditor, string assemblyPath, string[] searchDirectories); // Returns an array of windows metadata files (.winmd) that should be referenced when compiling scripts. // Only WinRT based platforms need these references. diff --git a/Editor/Mono/Networking/PlayerConnection/AttachToPlayerGUI.cs b/Editor/Mono/Networking/PlayerConnection/AttachToPlayerGUI.cs index fddc7584ed..aba9c7b95c 100644 --- a/Editor/Mono/Networking/PlayerConnection/AttachToPlayerGUI.cs +++ b/Editor/Mono/Networking/PlayerConnection/AttachToPlayerGUI.cs @@ -80,7 +80,7 @@ static class Content { public static readonly GUIContent EnterIPText = UnityEditor.EditorGUIUtility.TrTextContent(""); public static readonly GUIContent AutoconnectedPlayer = UnityEditor.EditorGUIUtility.TrTextContent("(Autoconnected Player)"); - public static readonly GUIContent ConnectingToPlayerMessage = UnityEditor.EditorGUIUtility.TrTextContent("Connecting to player...(this can take a while)"); + public static readonly GUIContent ConnectingToPlayerMessage = UnityEditor.EditorGUIUtility.TrTextContent("Connecting to player... (this can take a while)"); public static readonly string LocalHostProhibited = L10n.Tr(" (Localhost prohibited)"); public static readonly string VersionMismatch = L10n.Tr(" (Version mismatch)"); @@ -200,7 +200,10 @@ void AddAvailablePlayerConnections(GenericMenu menuOptions, ref bool hasOpenConn menuOptions.AddItem(new GUIContent(name), isConnected, () => { ProfilerDriver.connectedProfiler = guid; - SuccesfullyConnectedToPlayer(connectionName); + if (ProfilerDriver.connectedProfiler == guid) + { + SuccesfullyConnectedToPlayer(connectionName); + } }); else menuOptions.AddDisabledItem(new GUIContent(name), isConnected); diff --git a/Editor/Mono/Networking/PlayerConnection/EditorConnection.cs b/Editor/Mono/Networking/PlayerConnection/EditorConnection.cs index dd4fb50bef..ae6818fcbf 100644 --- a/Editor/Mono/Networking/PlayerConnection/EditorConnection.cs +++ b/Editor/Mono/Networking/PlayerConnection/EditorConnection.cs @@ -140,7 +140,7 @@ public void Send(Guid messageId, byte[] data, int playerId) { if (messageId == Guid.Empty) { - throw new ArgumentException("Cant be Guid.Empty", "messageId"); + throw new ArgumentException("Can not be Guid.Empty", "messageId"); } GetEditorConnectionNativeApi().SendMessage(messageId, data, playerId); @@ -151,6 +151,21 @@ public void Send(Guid messageId, byte[] data) Send(messageId, data, 0); } + public bool TrySend(Guid messageId, byte[] data, int playerId) + { + if (messageId == Guid.Empty) + { + throw new ArgumentException("Can not be Guid.Empty", "messageId"); + } + + return GetEditorConnectionNativeApi().TrySendMessage(messageId, data, playerId); + } + + public bool TrySend(Guid messageId, byte[] data) + { + return TrySend(messageId, data, 0); + } + public void DisconnectAll() { GetEditorConnectionNativeApi().DisconnectAll(); diff --git a/Editor/Mono/ObjectSelector.cs b/Editor/Mono/ObjectSelector.cs index 4206e04c18..ce39067d19 100644 --- a/Editor/Mono/ObjectSelector.cs +++ b/Editor/Mono/ObjectSelector.cs @@ -80,7 +80,10 @@ static class Styles const float kMinWidth = 200; const float kPreviewMargin = 5; const float kPreviewExpandedAreaHeight = 75; - float m_ToolbarHeight = 44; + static float kToolbarHeight => EditorGUI.kWindowToolbarHeight; + static float kTopAreaHeight => kToolbarHeight * 2; + const float kResizerHeight = 20f; + float m_PreviewSize = 0; float m_TopSize = 0; AnimBool m_ShowWidePreview = new AnimBool(); @@ -92,7 +95,7 @@ Rect listPosition { get { - return new Rect(0, m_ToolbarHeight, position.width, Mathf.Max(0f, m_TopSize - m_ToolbarHeight)); + return new Rect(0, kTopAreaHeight, position.width, Mathf.Max(0f, m_TopSize - kTopAreaHeight)); } } @@ -486,14 +489,14 @@ public static UnityObject GetInitialObject() // This is our search field void SearchArea() { - GUI.Label(new Rect(0, 0, position.width, m_ToolbarHeight), GUIContent.none, Styles.toolbarBack); + GUI.Label(new Rect(0, 0, position.width, kToolbarHeight), GUIContent.none, EditorStyles.toolbar); // ESC clears search field and removes it's focus. But if we get an esc event we only want to clear search field. // So we need special handling afterwards. bool wasEscape = Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Escape; GUI.SetNextControlName("SearchFilter"); - string searchFilter = EditorGUI.SearchField(new Rect(5, 5, position.width - 10, 15), m_SearchFilter); + string searchFilter = EditorGUI.ToolbarSearchField(new Rect(2, 2, position.width - 2, 16), m_SearchFilter, false); if (wasEscape && Event.current.type == EventType.Used) { @@ -521,7 +524,7 @@ void SearchArea() GUI.changed = false; // TAB BAR - GUILayout.BeginArea(new Rect(0, 26, position.width, m_ToolbarHeight - 26)); + GUILayout.BeginArea(new Rect(4, kToolbarHeight, position.width - 4, kToolbarHeight)); GUILayout.BeginHorizontal(); // Asset Tab @@ -566,7 +569,7 @@ void SearchArea() if (m_ListArea.CanShowThumbnails()) { EditorGUI.BeginChangeCheck(); - var newGridSize = (int)GUI.HorizontalSlider(new Rect(position.width - (60 + size.x), 26, 55, m_ToolbarHeight - 28), m_ListArea.gridSize, m_ListArea.minGridSize, m_ListArea.maxGridSize); + var newGridSize = (int)GUI.HorizontalSlider(new Rect(position.width - (60 + size.x), kToolbarHeight + GUI.skin.horizontalSlider.margin.top, 55, EditorGUI.kSingleLineHeight), m_ListArea.gridSize, m_ListArea.minGridSize, m_ListArea.maxGridSize); if (EditorGUI.EndChangeCheck()) { m_ListArea.gridSize = newGridSize; @@ -576,7 +579,7 @@ void SearchArea() if (m_IsShowingAssets) { EditorGUI.BeginChangeCheck(); - var skipHiddenPackages = GUI.Toggle(new Rect(position.width - size.x, 26, size.x, m_ToolbarHeight - 28), m_SkipHiddenPackages, Styles.packagesVisibilityContent, EditorStyles.toolbarButton); + var skipHiddenPackages = GUI.Toggle(new Rect(position.width - size.x, kToolbarHeight, size.x, EditorStyles.toolbarButton.fixedHeight), m_SkipHiddenPackages, Styles.packagesVisibilityContent, EditorStyles.toolbarButton); if (EditorGUI.EndChangeCheck()) { m_SkipHiddenPackages = skipHiddenPackages; @@ -731,7 +734,7 @@ void ResizeBottomPartOfWindow() GUI.changed = false; // Handle preview size - m_PreviewSize = m_PreviewResizer.ResizeHandle(position, kPreviewExpandedAreaHeight + kPreviewMargin * 2 - 20, kMinTopSize + 20, 20) + 20; + m_PreviewSize = m_PreviewResizer.ResizeHandle(position, kPreviewExpandedAreaHeight + kPreviewMargin * 2 - kResizerHeight, kMinTopSize + kResizerHeight, kResizerHeight) + kResizerHeight; m_TopSize = position.height - m_PreviewSize; bool open = PreviewIsOpen(); diff --git a/Editor/Mono/PackageUtility.bindings.cs b/Editor/Mono/PackageUtility.bindings.cs index 25e6074149..4118b4bcba 100644 --- a/Editor/Mono/PackageUtility.bindings.cs +++ b/Editor/Mono/PackageUtility.bindings.cs @@ -62,7 +62,7 @@ internal class PackageUtility public static extern void ExportPackage(string[] guids, string fileName); [NativeThrows] public static extern void ExportPackageAndPackageManagerManifest(string[] guids, string fileName); - public static extern ImportPackageItem[] ExtractAndPrepareAssetList(string packagePath, out string packageIconPath, out bool canPerformReInstall); + public static extern ImportPackageItem[] ExtractAndPrepareAssetList(string packagePath, out string packageIconPath, out bool canPerformReInstall, out string packageManagerDependenciesPath); [FreeFunction("DelayedImportPackageAssets")] public static extern void ImportPackageAssets(string packageName, ImportPackageItem[] items, bool performReInstall); diff --git a/Editor/Mono/PerceptionRemoting/HolographicEmulation/HolographicEmulationWindow.cs b/Editor/Mono/PerceptionRemoting/HolographicEmulation/HolographicEmulationWindow.cs index cfa4ada8b5..e15b7253c3 100644 --- a/Editor/Mono/PerceptionRemoting/HolographicEmulation/HolographicEmulationWindow.cs +++ b/Editor/Mono/PerceptionRemoting/HolographicEmulation/HolographicEmulationWindow.cs @@ -27,9 +27,11 @@ internal class HolographicEmulationWindow : EditorWindow [SerializeField] private EmulationMode m_Mode = EmulationMode.None; [SerializeField] + private RemoteDeviceVersion m_DeviceVersion = RemoteDeviceVersion.V1; + [SerializeField] private int m_RoomIndex = 0; [SerializeField] - private PlaymodeInputType m_InputType = PlaymodeInputType.LeftController; + private PlaymodeInputType m_InputType = PlaymodeInputType.RightHand; [SerializeField] private string m_RemoteMachineAddress = ""; [SerializeField] @@ -46,6 +48,7 @@ internal class HolographicEmulationWindow : EditorWindow private static GUIContent s_ConnectionStatusText = EditorGUIUtility.TrTextContent("Connection Status"); private static GUIContent s_EmulationModeText = EditorGUIUtility.TrTextContent("Emulation Mode"); + private static GUIContent s_DeviceVersionText = EditorGUIUtility.TrTextContent("Device Version"); private static GUIContent s_RoomText = EditorGUIUtility.TrTextContent("Room"); private static GUIContent s_InputText = EditorGUIUtility.TrTextContent("Simulated Input"); private static GUIContent s_RemoteMachineText = EditorGUIUtility.TrTextContent("Remote Machine"); @@ -67,6 +70,12 @@ internal class HolographicEmulationWindow : EditorWindow EditorGUIUtility.TrTextContent("Simulate in Editor") }; + private static GUIContent[] s_DeviceVersionStrings = new GUIContent[] + { + EditorGUIUtility.TrTextContent("HoloLens (1st Gen)"), + EditorGUIUtility.TrTextContent("HoloLens 2") + }; + private static GUIContent[] s_RoomStrings = new GUIContent[] { EditorGUIUtility.TrTextContent("None"), @@ -88,7 +97,12 @@ internal class HolographicEmulationWindow : EditorWindow internal EmulationMode emulationMode { get { return m_Mode; } - set { m_Mode = value; Repaint(); } + set + { + HolographicAutomation.SetEmulationMode(value); + m_Mode = value; + Repaint(); + } } internal static void Init() @@ -101,17 +115,11 @@ internal static void Init() private void OnEnable() { titleContent = EditorGUIUtility.TrTextContent("Holographic"); - EditorApplication.playModeStateChanged += OnPlayModeStateChanged; m_InPlayMode = EditorApplication.isPlayingOrWillChangePlaymode; m_RemoteMachineHistory = EditorPrefs.GetString("HolographicRemoting.RemoteMachineHistory").Split(','); } - private void OnDisable() - { - EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; - } - private void LoadCurrentRoom() { if (m_RoomIndex == 0) @@ -121,51 +129,10 @@ private void LoadCurrentRoom() HolographicAutomation.LoadRoom(roomPath + s_RoomStrings[m_RoomIndex].text + ".xef"); } - private void InitializeSimulation() - { - Disconnect(); - - HolographicAutomation.Initialize(); - - LoadCurrentRoom(); - } - - private void OnPlayModeStateChanged(PlayModeStateChange state) - { - if (!IsWindowsMixedRealityCurrentTarget()) - return; - - bool wasPlaying = m_InPlayMode; - m_InPlayMode = EditorApplication.isPlayingOrWillChangePlaymode; - - if (m_InPlayMode && !wasPlaying) - { - HolographicAutomation.SetEmulationMode(m_Mode); - switch (m_Mode) - { - case EmulationMode.Simulated: - InitializeSimulation(); - break; - case EmulationMode.RemoteDevice: - break; - } - } - else if (!m_InPlayMode && wasPlaying) - { - switch (m_Mode) - { - case EmulationMode.Simulated: - HolographicAutomation.Shutdown(); - break; - - case EmulationMode.RemoteDevice: - break; - } - } - } - private void Connect() { + HolographicAutomation.SetEmulationMode(m_Mode); + PerceptionRemoting.SetRemoteDeviceVersion(m_DeviceVersion); PerceptionRemoting.SetVideoEncodingParameters(m_MaxBitrateKbps); PerceptionRemoting.SetEnableVideo(m_EnableVideo); PerceptionRemoting.SetEnableAudio(m_EnableAudio); @@ -240,6 +207,8 @@ private void UpdateRemoteMachineHistory() private void RemotingPreferencesOnGUI() { + m_DeviceVersion = (RemoteDeviceVersion)EditorGUILayout.Popup(s_DeviceVersionText, (int)m_DeviceVersion, s_DeviceVersionStrings); + EditorGUI.BeginChangeCheck(); m_RemoteMachineAddress = EditorGUILayout.DelayedTextFieldDropDown(s_RemoteMachineText, m_RemoteMachineAddress, m_RemoteMachineHistory); if (EditorGUI.EndChangeCheck()) @@ -329,10 +298,12 @@ private bool IsWindowsMixedRealityCurrentTarget() private void DrawRemotingMode() { EditorGUI.BeginChangeCheck(); + EmulationMode previousMode = m_Mode; m_Mode = (EmulationMode)EditorGUILayout.Popup(s_EmulationModeText, (int)m_Mode, s_ModeStrings); - if (EditorGUI.EndChangeCheck() && m_Mode != EmulationMode.RemoteDevice) + if (EditorGUI.EndChangeCheck()) { - Disconnect(); + if (previousMode == EmulationMode.RemoteDevice) + Disconnect(); } } diff --git a/Editor/Mono/PlayerSettings.bindings.cs b/Editor/Mono/PlayerSettings.bindings.cs index eedf4565c2..545b64a70c 100644 --- a/Editor/Mono/PlayerSettings.bindings.cs +++ b/Editor/Mono/PlayerSettings.bindings.cs @@ -524,6 +524,8 @@ public static bool singlePassStereoRendering // Restrict standalone players to a single concurrent running instance. public static extern bool forceSingleInstance { get; set; } + public static extern bool useFlipModelSwapchain { get; set; } + [NativeProperty(TargetType = TargetType.Field)] public static extern bool openGLRequireES31 { @@ -950,12 +952,22 @@ public static UInt32 xboxSpeechDB public static extern GraphicsJobMode graphicsJobMode { get; set; } - [StaticAccessor("GetPlayerSettings().GetEditorOnly()")] + [Obsolete("GetPlatformVuforiaEnabled(BuildTargetGroup targetGroup) has been deprecated. Use vuforiaEnabled instead.")] + [StaticAccessor("PlayerSettingsBindings", StaticAccessorType.DoubleColon)] public static extern bool GetPlatformVuforiaEnabled(BuildTargetGroup targetGroup); - [StaticAccessor("GetPlayerSettings().GetEditorOnlyForUpdate()")] + [Obsolete("SetPlatformVuforiaEnabled(BuildTargetGroup targetGroup, bool enabled) has been deprecated. Use vuforiaEnabled instead.")] + [StaticAccessor("PlayerSettingsBindings", StaticAccessorType.DoubleColon)] public static extern void SetPlatformVuforiaEnabled(BuildTargetGroup targetGroup, bool enabled); + public static extern bool vuforiaEnabled + { + [StaticAccessor("GetPlayerSettings().GetEditorOnly()")] + get; + [StaticAccessor("GetPlayerSettings().GetEditorOnlyForUpdate()")] + set; + } + [StaticAccessor("GetPlayerSettings()")] public static extern bool GetWsaHolographicRemotingEnabled(); diff --git a/Editor/Mono/PlayerSettingsIOS.bindings.cs b/Editor/Mono/PlayerSettingsIOS.bindings.cs index 02da03eabf..80e42de233 100644 --- a/Editor/Mono/PlayerSettingsIOS.bindings.cs +++ b/Editor/Mono/PlayerSettingsIOS.bindings.cs @@ -91,6 +91,8 @@ public enum iOSAppInBackgroundBehavior { Custom = -1, Suspend = 0, + + [Obsolete("UIApplicationExitsOnSuspend is no longer supported in iOS 13, use Custom or Suspend instead (UnityUpgradable) -> Custom", true)] Exit = 1, } @@ -368,9 +370,15 @@ public static UnityEngine.iOS.SystemGestureDeferMode deferSystemGesturesMode public static bool hideHomeButton { get; set; } [NativeProperty("IOSAppInBackgroundBehavior")] - private extern static int appInBackgroundBehaviorInternal { get; set; } + private extern static int appInBackgroundBehaviorInternal + { + [FreeFunction("PlayerSettingsIOSBindings::GetAppInBackgroundBehavior")] + get; + + [FreeFunction("PlayerSettingsIOSBindings::SetAppInBackgroundBehavior")] + set; + } - [NativeProperty("IOSAppInBackgroundBehavior")] public static iOSAppInBackgroundBehavior appInBackgroundBehavior { get { return (iOSAppInBackgroundBehavior)appInBackgroundBehaviorInternal; } diff --git a/Editor/Mono/PlayerSettingsSwitch.bindings.cs b/Editor/Mono/PlayerSettingsSwitch.bindings.cs index 37613967b1..44ff9ef970 100644 --- a/Editor/Mono/PlayerSettingsSwitch.bindings.cs +++ b/Editor/Mono/PlayerSettingsSwitch.bindings.cs @@ -97,7 +97,8 @@ public enum RatingCategories PEGIBBFC = 8, Russian = 9, ACB = 10, - OFLC = 11 + OFLC = 11, + IARCGeneric = 12, } private enum SupportedNpadStyleBits diff --git a/Editor/Mono/PointEditor.cs b/Editor/Mono/PointEditor.cs index 0f801c963f..d709d6a6cc 100644 --- a/Editor/Mono/PointEditor.cs +++ b/Editor/Mono/PointEditor.cs @@ -175,8 +175,10 @@ public static bool SelectPoints(IEditablePoint points, Transform cloudTransform, // Go over all the points and add them if they are inside the rect for (int i = 0; i < points.Count; i++) { - var point = HandleUtility.WorldToGUIPoint(points.GetPosition(i)); - if (r.Contains(point)) + var point = HandleUtility.WorldToGUIPointWithDepth(points.GetPosition(i)); + + // the point has to be within the selection and in front of the camera + if (r.Contains(point) && point.z > 0.0f) { if (EditorGUI.actionKey) { diff --git a/Editor/Mono/PostprocessScene.cs b/Editor/Mono/PostprocessScene.cs index 71891c4fc0..04ee821e7a 100644 --- a/Editor/Mono/PostprocessScene.cs +++ b/Editor/Mono/PostprocessScene.cs @@ -2,8 +2,11 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License +using System; using UnityEngine; using UnityEditor.Build; +using System.Text; +using UnityEngine.SceneManagement; namespace UnityEditor { @@ -16,7 +19,50 @@ public void OnProcessScene(UnityEngine.SceneManagement.Scene scene, Build.Report PlayerSettings.GetBatchingForPlatform(EditorUserBuildSettings.activeBuildTarget, out staticBatching, out dynamicBatching); if (staticBatching != 0) { - InternalStaticBatchingUtility.Combine(null, true, true); + InternalStaticBatchingUtility.Combine(null, true, true, new EditorStaticBatcherGOSorter(scene)); + } + } + + internal class EditorStaticBatcherGOSorter : InternalStaticBatchingUtility.StaticBatcherGOSorter + { + Scene scene; + + public EditorStaticBatcherGOSorter(Scene scene) + { + this.scene = scene; + } + + private static long GetStableHash(UnityEngine.Object instance, string guid) + { + var lfid = UnityEditor.Unsupported.GetFileIDHint(instance); + + using (var md5Hash = System.Security.Cryptography.MD5.Create()) + { + var bytes = Encoding.ASCII.GetBytes(guid); + md5Hash.TransformBlock(bytes, 0, bytes.Length, null, 0); + bytes = BitConverter.GetBytes(lfid); + md5Hash.TransformFinalBlock(bytes, 0, bytes.Length); + return BitConverter.ToInt64(md5Hash.Hash, 0); + } + } + + public override long GetMaterialId(Renderer renderer) + { + if (renderer == null || renderer.sharedMaterial == null) + return 0; + + string path = AssetDatabase.GetAssetPath(renderer.sharedMaterial); + string guid = AssetDatabase.AssetPathToGUID(path); + return GetStableHash(renderer.sharedMaterial, guid); + } + + public override long GetRendererId(Renderer renderer) + { + if (renderer == null) + return -1; + + string guid = AssetDatabase.AssetPathToGUID(scene.path); + return GetStableHash(renderer, guid); } } } diff --git a/Editor/Mono/Prefabs/PrefabImporterEditor.cs b/Editor/Mono/Prefabs/PrefabImporterEditor.cs index d31b55d9cd..b1a0e91ede 100644 --- a/Editor/Mono/Prefabs/PrefabImporterEditor.cs +++ b/Editor/Mono/Prefabs/PrefabImporterEditor.cs @@ -6,6 +6,7 @@ using UnityEditor.Experimental.AssetImporters; using UnityEditor.Experimental.SceneManagement; using UnityEditor.SceneManagement; +using System.Collections.Generic; namespace UnityEditor { @@ -13,12 +14,170 @@ namespace UnityEditor [CanEditMultipleObjects] internal class PrefabImporterEditor : AssetImporterEditor { - static GUIContent s_OpenContent = EditorGUIUtility.TrTextContent("Open Prefab"); - static GUIContent s_BaseContent = EditorGUIUtility.TrTextContent("Base"); - static string s_LocalizedTitleMultiplePrefabs = L10n.Tr("Prefab Assets"); - static string s_LocalizedTitleSinglePrefab = L10n.Tr("Prefab Asset"); + static class Styles + { + public static GUIContent openContent = EditorGUIUtility.TrTextContent("Open Prefab"); + public static GUIContent openHelpText = EditorGUIUtility.TrTextContent("Open Prefab for full editing support."); + public static GUIContent missingScriptsHelpText = EditorGUIUtility.TrTextContent("Prefab has missing scripts. Open Prefab to fix the issue."); + public static GUIContent multiSelectionMissingScriptsHelpText = EditorGUIUtility.TrTextContent("Some of the selected Prefabs have missing scripts and needs to be fixed before editing them. Click to Open Prefab to fix the issue."); + public static GUIContent savingFailedHelpText = EditorGUIUtility.TrTextContent("Saving has failed. Check the Console window to get more insight into what needs to be fixed on the Prefab Asset.\n\nOpen Prefab to fix the issue."); + public static GUIContent baseContent = EditorGUIUtility.TrTextContent("Base"); + public static string localizedTitleMultiplePrefabs = L10n.Tr("Prefab Assets"); + public static string localizedTitleSinglePrefab = L10n.Tr("Prefab Asset"); + public static GUIStyle openButtonStyle = "AC Button"; + } int m_HasMixedBaseVariants = -1; + double m_NextUpdate; + List m_PrefabsWithMissingScript = new List(); + bool m_SavingHasFailed; + List m_TempComponentsResults = new List(); + + public override bool showImportedObject { get { return !hasMissingScripts; } } + + public override bool UseDefaultMargins() + { + return false; + } + + bool isTextFieldCaretShowing + { + get { return EditorGUI.IsEditingTextField() && !EditorGUIUtility.textFieldHasSelection; } + } + + bool readyToAutoSave + { + get { return !m_SavingHasFailed && !hasMissingScripts && GUIUtility.hotControl == 0 && !isTextFieldCaretShowing && !EditorApplication.isCompiling; } + } + + bool hasMissingScripts + { + get { return m_PrefabsWithMissingScript.Count > 0; } + } + + public override void OnEnable() + { + base.OnEnable(); + EditorApplication.update += Update; + } + + public override void OnDisable() + { + EditorApplication.update -= Update; + base.OnDisable(); + } + + protected override void Awake() + { + base.Awake(); + + foreach (var prefabAssetRoot in assetTargets) + { + if (PrefabUtility.HasInvalidComponent(prefabAssetRoot)) + { + m_PrefabsWithMissingScript.Add(AssetDatabase.GetAssetPath(prefabAssetRoot)); + } + } + m_PrefabsWithMissingScript.Sort(); + } + + void OnDestroy() + { + // Ensure to save unsaved changes (regardless of hotcontrol etc) + if (!m_SavingHasFailed && !hasMissingScripts) + SaveDirtyPrefabAssets(); + } + + void Update() + { + var time = EditorApplication.timeSinceStartup; + if (time > m_NextUpdate) + { + m_NextUpdate = time + 0.2; + + if (readyToAutoSave && HasDirtyPrefabAssets()) + SaveDirtyPrefabAssets(); + } + } + + // Internal for testing framework + internal void SaveDirtyPrefabAssets() + { + if (assetTargets == null) + return; + + if (assetTarget == null) + return; + + foreach (var asset in assetTargets) + { + // The asset could have been deleted when this method is called from OnDestroy(). + // E.g delete the selected prefab asset from the Project Browser. + if (asset == null) + continue; + + if (!EditorUtility.IsPersistent(asset)) + continue; + + if (!(asset is GameObject)) + continue; + + var rootGameObject = (GameObject)asset; + if (IsDirty(rootGameObject)) + { + bool savedSuccesfully; + PrefabUtility.SavePrefabAsset(rootGameObject, out savedSuccesfully); + if (!savedSuccesfully) + { + string title = L10n.Tr("Saving Failed"); + string message = L10n.Tr("Check the Console window to get more insight into what needs to be fixed on the Prefab Asset.\n\nYou can open Prefab Mode to fix any issues on child GameObjects"); + EditorUtility.DisplayDialog(title, message, L10n.Tr("OK")); + + m_SavingHasFailed = true; + return; + } + } + } + } + + internal bool HasDirtyPrefabAssets() + { + if (assetTarget == null) + return false; + + if (typeof(GameObject) != assetTarget.GetType()) + return false; + + // We just check one target since we assume that a multi-edit will + // always edit that target. So no need to spend resources on checking + // all targets in multiselection. + return IsDirty((GameObject)assetTarget); + } + + bool IsDirty(GameObject prefabAssetRoot) + { + if (prefabAssetRoot == null) + return false; + + if (EditorUtility.IsDirty(prefabAssetRoot)) + return true; + + // For Prefab Variant Asset we need to also check if the instance handle is dirty + // since this happens when the list of removed component changes + var instanceHandle = PrefabUtility.GetPrefabInstanceHandle(prefabAssetRoot); + if (instanceHandle != null) + if (EditorUtility.IsDirty(instanceHandle)) + return true; + + prefabAssetRoot.GetComponents(m_TempComponentsResults); + foreach (var component in m_TempComponentsResults) + { + if (EditorUtility.IsDirty(component)) + return true; + } + + return false; + } void CacheHasMixedBaseVariants() { @@ -43,28 +202,31 @@ void CacheHasMixedBaseVariants() protected override bool needsApplyRevert => false; - public override bool showImportedObject { get { return false; } } - internal override string targetTitle { get { if (assetTargets == null || assetTargets.Length == 1 || !m_AllowMultiObjectAccess) - return assetTarget != null ? assetTarget.name : s_LocalizedTitleSinglePrefab; + return assetTarget != null ? assetTarget.name + " (" + Styles.localizedTitleSinglePrefab + ")" : Styles.localizedTitleSinglePrefab; else - return assetTargets.Length + " " + s_LocalizedTitleMultiplePrefabs; + return assetTargets.Length + " " + Styles.localizedTitleMultiplePrefabs; } } internal override void OnHeaderControlsGUI() { + if (assetTarget is DefaultAsset) + { + return; + } + var variantBase = PrefabUtility.GetCorrespondingObjectFromSource(assetTarget); if (variantBase != null) { using (new EditorGUI.DisabledScope(true)) { CacheHasMixedBaseVariants(); - GUILayout.Label(s_BaseContent); + GUILayout.Label(Styles.baseContent); EditorGUI.showMixedValue = m_HasMixedBaseVariants == 1; EditorGUILayout.ObjectField(variantBase, typeof(GameObject), false); EditorGUI.showMixedValue = false; @@ -79,6 +241,13 @@ internal override void OnHeaderControlsGUI() public override void OnInspectorGUI() { + if (assetTarget is DefaultAsset) + { + return; + } + + EditorGUILayout.BeginVertical(EditorStyles.inspectorFullWidthMargins); + // Allow opening prefab even if file is not open for edit. // For things with explicit save operations (scenes, prefabs) we allow editing // and handle the potential version control conflict at the time when the user saves. @@ -86,15 +255,63 @@ public override void OnInspectorGUI() GUI.enabled = true; using (new EditorGUI.DisabledScope(assetTargets.Length > 1)) { - if (GUILayout.Button(s_OpenContent)) + GUILayout.Space(10); + + EditorGUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + if (GUILayout.Button(Styles.openContent, Styles.openButtonStyle)) { // We only support opening one prefab at a time (so do not use 'targets') PrefabStageUtility.OpenPrefab(AssetDatabase.GetAssetPath(assetTarget), null, StageNavigationManager.Analytics.ChangeType.EnterViaAssetInspectorOpenButton); GUIUtility.ExitGUI(); } + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + + GUILayout.Space(5); + + if (!hasMissingScripts && !m_SavingHasFailed) + { + EditorGUILayout.HelpBox(Styles.openHelpText.text, MessageType.Info, true); + } } GUI.enabled = wasEnabled; + + if (hasMissingScripts) + { + if (assetTargets.Length > 1) + { + // List all assets that have missing scripts (but only if we have a multi-selection) + GUILayout.Space(5); + EditorGUILayout.HelpBox(Styles.multiSelectionMissingScriptsHelpText.text, MessageType.Warning, true); + using (new EditorGUILayout.HorizontalScope()) + { + GUILayout.Space(10); + + using (new EditorGUILayout.VerticalScope()) + { + foreach (var prefabAssetPath in m_PrefabsWithMissingScript) + { + if (GUILayout.Button(prefabAssetPath, EditorStyles.label)) + { + PrefabStageUtility.OpenPrefab(prefabAssetPath); + } + } + } + } + } + else + { + EditorGUILayout.HelpBox(Styles.missingScriptsHelpText.text, MessageType.Warning, true); + } + } + else if (m_SavingHasFailed) + { + EditorGUILayout.HelpBox(Styles.savingFailedHelpText.text, MessageType.Warning, true); + } + + EditorGUILayout.EndVertical(); } } } diff --git a/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverride.cs b/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverride.cs index 75941ca0a5..9f8e8a0e3e 100644 --- a/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverride.cs +++ b/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverride.cs @@ -49,7 +49,9 @@ internal void HandleApplyMenuItems(GenericMenu menu, GenericMenu.MenuFunction2 a menu.AddDisabledItem(menuItemContent); else menu.AddItem(menuItemContent, false, applyAction, prefabAssetPath); - }); + }, + false, + true); } } diff --git a/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesTreeView.cs b/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesTreeView.cs index c04b58d5b1..8386ab80a2 100644 --- a/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesTreeView.cs +++ b/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesTreeView.cs @@ -708,6 +708,8 @@ void Apply(object prefabAssetPathObject) if (!PrefabUtility.PromptAndCheckoutPrefabIfNeeded(prefabAssetPath, PrefabUtility.SaveVerb.Apply)) return; m_Modification.Apply(prefabAssetPath); + EditorUtility.ForceRebuildInspectors(); // handles applying RemovedComponents + UpdateAndClose(); } diff --git a/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesUtility.cs b/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesUtility.cs index ef8f72f118..1adf18cc8c 100644 --- a/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesUtility.cs +++ b/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesUtility.cs @@ -105,6 +105,10 @@ static void CheckForAddedComponents(Transform transform, object userData) if (component == null) continue; + // Don't list DontSave objects as they won't get applied or reverted. + if ((component.hideFlags & HideFlags.DontSaveInEditor) != 0) + continue; + bool isAddedObject = PrefabUtility.GetCorrespondingObjectFromSource(component) == null; if (isAddedObject) { @@ -121,15 +125,25 @@ public static List GetRemovedComponents(GameObject prefabInsta var prefabInstanceRoot = PrefabUtility.GetOutermostPrefabInstanceRoot(prefabInstance); // From root of asset traverse all children and detect any Components that are not present on the instance object (these must be deleted) - TransformVisitor transformVisitor = new TransformVisitor(); var removedComponents = new List(); if (PrefabUtility.IsDisconnectedFromPrefabAsset(prefabInstance)) return removedComponents; - + TransformVisitor transformVisitor = new TransformVisitor(); transformVisitor.VisitAll(prefabInstanceRoot.transform, CheckForRemovedComponents, removedComponents); return removedComponents; } + public static List GetRemovedComponentsForSingleGameObject(GameObject prefabInstance) + { + ThrowExceptionIfNullOrNotPartOfPrefabInstance(prefabInstance); + + var removedComponents = new List(); + if (PrefabUtility.IsDisconnectedFromPrefabAsset(prefabInstance)) + return removedComponents; + CheckForRemovedComponents(prefabInstance.transform, removedComponents); + return removedComponents; + } + static void CheckForRemovedComponents(Transform transform, object userData) { GameObject instanceGameObject = transform.gameObject; @@ -196,6 +210,10 @@ public static List GetAddedGameObjects(GameObject prefabInstanc static bool CheckForAddedGameObjectAndIfSoAddItAndReturnFalse(Transform transform, object userData) { + // Don't list DontSave objects or their children as they won't get applied or reverted. + if ((transform.gameObject.hideFlags & HideFlags.DontSaveInEditor) != 0) + return false; + var addedGameObjectUserData = (AddedGameObjectUserData)userData; if (IsAddedGameObject(addedGameObjectUserData.contextGameObject, transform.gameObject)) { diff --git a/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesWindow.cs b/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesWindow.cs index 64ac69d808..6231cb1044 100644 --- a/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesWindow.cs +++ b/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesWindow.cs @@ -287,6 +287,12 @@ public override void OnGUI(Rect rect) GUILayout.EndHorizontal(); } + struct ApplyAllUndo + { + public GameObject correspondingSourceObject; + public HashSet prefabHierarchy; + }; + bool ApplyAll() { // Collect Prefab Asset paths and also check if there's more than one of the same. @@ -313,11 +319,37 @@ bool ApplyAll() if (!PrefabUtility.PromptAndCheckoutPrefabIfNeeded(prefabAssetPaths.ToArray(), PrefabUtility.SaveVerb.Apply)) return false; + var undoStructs = new List(); + var actionName = "ApplyAll"; + for (var i = 0; i < m_SelectedGameObjects.Length; i++) + { + var us = new ApplyAllUndo(); + us.correspondingSourceObject = (GameObject)PrefabUtility.GetCorrespondingObjectFromSource(m_SelectedGameObjects[i]); + Undo.RegisterFullObjectHierarchyUndo(us.correspondingSourceObject, actionName); // handles changes to existing objects and object what will be deleted but not objects that are created + GameObject prefabInstanceRoot = PrefabUtility.GetOutermostPrefabInstanceRoot(m_SelectedGameObjects[i]); + Undo.RegisterFullObjectHierarchyUndo(prefabInstanceRoot, actionName); + + us.prefabHierarchy = new HashSet(); + PrefabUtility.GetObjectListFromHierarchy(us.prefabHierarchy, us.correspondingSourceObject); + undoStructs.Add(us); + } + // Apply sequentially. AssetDatabase.StartAssetEditing(); - for (int i = 0; i < m_SelectedGameObjects.Length; i++) - PrefabUtility.ApplyPrefabInstance(m_SelectedGameObjects[i], InteractionMode.UserAction); - AssetDatabase.StopAssetEditing(); + try + { + foreach (var t in m_SelectedGameObjects) + PrefabUtility.ApplyPrefabInstance(t, InteractionMode.UserAction); + } + finally + { + AssetDatabase.StopAssetEditing(); + } + + foreach (var t in undoStructs) + { + PrefabUtility.RegisterNewObjects(t.correspondingSourceObject, t.prefabHierarchy, actionName); + } EditorUtility.ForceRebuildInspectors(); return true; @@ -328,7 +360,6 @@ bool RevertAll() for (int i = 0; i < m_SelectedGameObjects.Length; i++) PrefabUtility.RevertPrefabInstance(m_SelectedGameObjects[i], InteractionMode.UserAction); - EditorUtility.ForceRebuildInspectors(); return true; } diff --git a/Editor/Mono/Prefabs/PrefabUtility.bindings.cs b/Editor/Mono/Prefabs/PrefabUtility.bindings.cs index 7ea7316f2a..dadd85a9b6 100644 --- a/Editor/Mono/Prefabs/PrefabUtility.bindings.cs +++ b/Editor/Mono/Prefabs/PrefabUtility.bindings.cs @@ -180,7 +180,7 @@ internal static GameObject CreateVariant(GameObject assetRoot, string path) extern private static GameObject SaveAsPrefabAssetAndConnect_Internal([NotNull] GameObject root, string path, out bool success); [StaticAccessor("PrefabUtilityBindings", StaticAccessorType.DoubleColon)] - extern private static GameObject SavePrefabAsset_Internal([NotNull] GameObject root); + extern private static GameObject SavePrefabAsset_Internal([NotNull] GameObject root, out bool success); internal static void AddGameObjectsToPrefabAndConnect(GameObject[] gameObjects, Object targetPrefab) { diff --git a/Editor/Mono/Prefabs/PrefabUtility.cs b/Editor/Mono/Prefabs/PrefabUtility.cs index b5092f6218..49e9f55756 100644 --- a/Editor/Mono/Prefabs/PrefabUtility.cs +++ b/Editor/Mono/Prefabs/PrefabUtility.cs @@ -158,7 +158,7 @@ internal static void ExtractMaterialsFromAsset(Object[] targets, string destinat } } - private static void GetObjectListFromHierarchy(HashSet hierarchyInstanceIDs, GameObject gameObject) + internal static void GetObjectListFromHierarchy(HashSet hierarchyInstanceIDs, GameObject gameObject) { Transform transform = null; List components = new List(); @@ -221,7 +221,7 @@ private static void CollectAddedObjects(GameObject gameObject, HashSet hier } } - private static void RegisterNewObjects(GameObject newHierarchy, HashSet hierarchyInstanceIDs, string actionName) + internal static void RegisterNewObjects(GameObject newHierarchy, HashSet hierarchyInstanceIDs, string actionName) { var danglingObjects = new List(); @@ -286,7 +286,7 @@ private static void RegisterNewObjects(GameObject newHierarchy, HashSet hie } } - static void ThrowExceptionIfNotValidNonPersistentPrefabInstanceObject(Object prefabInstanceObject) + static void ThrowExceptionIfNotValidPrefabInstanceObject(Object prefabInstanceObject, bool isApply) { if (!(prefabInstanceObject is GameObject || prefabInstanceObject is Component)) throw new ArgumentException("Calling apply or revert methods on an object which is not a GameObject or Component is not supported.", nameof(prefabInstanceObject)); @@ -294,18 +294,21 @@ static void ThrowExceptionIfNotValidNonPersistentPrefabInstanceObject(Object pre throw new NullReferenceException("Cannot apply or revert object. Object is null."); if (!PrefabUtility.IsPartOfPrefabInstance(prefabInstanceObject)) throw new ArgumentException("Calling apply or revert methods on an object which is not part of a Prefab instance is not supported.", nameof(prefabInstanceObject)); - ThrowExceptionIfInstanceIsPersistent(prefabInstanceObject); + + // We support revert operations on Prefab Assets, but not apply operations. + if (isApply) + ThrowExceptionIfInstanceIsPersistent(prefabInstanceObject); } static void ThrowExceptionIfInstanceIsPersistent(Object prefabInstanceObject) { if (EditorUtility.IsPersistent(prefabInstanceObject)) - throw new ArgumentException("Calling apply or revert methods on an instance which is part of a Prefab Asset is not supported.", nameof(prefabInstanceObject)); + throw new ArgumentException("Calling apply methods on an instance which is part of a Prefab Asset is not supported.", nameof(prefabInstanceObject)); } public static void RevertPrefabInstance(GameObject instanceRoot, InteractionMode action) { - ThrowExceptionIfNotValidNonPersistentPrefabInstanceObject(instanceRoot); + ThrowExceptionIfNotValidPrefabInstanceObject(instanceRoot, false); bool isDisconnected = PrefabUtility.IsDisconnectedFromPrefabAsset(instanceRoot); @@ -337,7 +340,7 @@ public static void ApplyPrefabInstance(GameObject instanceRoot, InteractionMode { DateTime startTime = DateTime.UtcNow; - ThrowExceptionIfNotValidNonPersistentPrefabInstanceObject(instanceRoot); + ThrowExceptionIfNotValidPrefabInstanceObject(instanceRoot, true); GameObject prefabInstanceRoot = GetOutermostPrefabInstanceRoot(instanceRoot); var isDisconnected = GetPrefabInstanceHandle(prefabInstanceRoot) == null; @@ -397,7 +400,7 @@ public static void ApplyPropertyOverride(SerializedProperty instanceProperty, st DateTime startTime = DateTime.UtcNow; Object prefabInstanceObject = instanceProperty.serializedObject.targetObject; - ThrowExceptionIfNotValidNonPersistentPrefabInstanceObject(prefabInstanceObject); + ThrowExceptionIfNotValidPrefabInstanceObject(prefabInstanceObject, true); ApplyPropertyOverrides(prefabInstanceObject, instanceProperty, assetPath, true, action); @@ -497,12 +500,43 @@ static void ApplyPropertyOverrides(Object prefabInstanceObject, SerializedProper } } - // Write modified value to prefab source object. - for (int i = 0; i < serializedObjects.Count; i++) + // Ensure importing of saved Prefab Assets only kicks in after all Prefab Asset have been saved + AssetDatabase.StartAssetEditing(); + + try { - serializedObjects[i].ApplyModifiedProperties(); - if (action == InteractionMode.UserAction) - Undo.FlushUndoRecordObjects(); // flush'es ensure that SavePrefab() on undo/redo on the source happens in the right order + // Write modified value to prefab source object. + for (int i = 0; i < serializedObjects.Count; i++) + { + if (serializedObjects[i].ApplyModifiedProperties()) + SaveChangesToPrefabFileIfPersistent(serializedObjects[i]); + + if (action == InteractionMode.UserAction) + Undo.FlushUndoRecordObjects(); // flush'es ensure that SavePrefab() on undo/redo on the source happens in the right order + } + } + finally + { + AssetDatabase.StopAssetEditing(); + } + } + + static void SaveChangesToPrefabFileIfPersistent(SerializedObject serializedObject) + { + if (!EditorUtility.IsPersistent(serializedObject.targetObject)) + return; + + GameObject go = serializedObject.targetObject as GameObject; + if (go == null) + { + var cmp = serializedObject.targetObject as Component; + if (cmp != null) + go = cmp.gameObject; + } + + if (go != null) + { + SavePrefabAsset(go.transform.root.gameObject); } } @@ -670,7 +704,7 @@ static void ApplySingleProperty( public static void RevertPropertyOverride(SerializedProperty instanceProperty, InteractionMode action) { Object prefabInstanceObject = instanceProperty.serializedObject.targetObject; - ThrowExceptionIfNotValidNonPersistentPrefabInstanceObject(prefabInstanceObject); + ThrowExceptionIfNotValidPrefabInstanceObject(prefabInstanceObject, false); instanceProperty.prefabOverride = false; // Because prefabOverride changed ApplyModifiedProperties will do a prefab merge causing the revert. @@ -684,7 +718,7 @@ public static void ApplyObjectOverride(Object instanceComponentOrGameObject, str { DateTime startTime = DateTime.UtcNow; - ThrowExceptionIfNotValidNonPersistentPrefabInstanceObject(instanceComponentOrGameObject); + ThrowExceptionIfNotValidPrefabInstanceObject(instanceComponentOrGameObject, true); ApplyPropertyOverrides(instanceComponentOrGameObject, null, assetPath, false, action); @@ -700,7 +734,7 @@ public static void ApplyObjectOverride(Object instanceComponentOrGameObject, str public static void RevertObjectOverride(Object instanceComponentOrGameObject, InteractionMode action) { - ThrowExceptionIfNotValidNonPersistentPrefabInstanceObject(instanceComponentOrGameObject); + ThrowExceptionIfNotValidPrefabInstanceObject(instanceComponentOrGameObject, false); if (action == InteractionMode.UserAction) Undo.RegisterCompleteObjectUndo(instanceComponentOrGameObject, "Revert component property overrides"); @@ -771,8 +805,6 @@ public static void RevertAddedComponent(Component component, InteractionMode act if (!PrefabUtility.IsAddedComponentOverride(component)) throw new ArgumentException("Cannot revert added component. Component is not an added component override on a Prefab instance.", nameof(component)); - ThrowExceptionIfInstanceIsPersistent(component); - if (action == InteractionMode.UserAction) { string dependentComponents = string.Join( @@ -827,7 +859,7 @@ public static void ApplyRemovedComponent(GameObject instanceGameObject, Componen { DateTime startTime = DateTime.UtcNow; - ThrowExceptionIfNotValidNonPersistentPrefabInstanceObject(instanceGameObject); + ThrowExceptionIfNotValidPrefabInstanceObject(instanceGameObject, true); if (assetComponent == null) throw new ArgumentNullException(nameof(assetComponent), "Prefab source may not be null."); @@ -884,7 +916,7 @@ private static void RemoveRemovedComponentOverride(Object instanceObject, Compon public static void RevertRemovedComponent(GameObject instanceGameObject, Component assetComponent, InteractionMode action) { - ThrowExceptionIfNotValidNonPersistentPrefabInstanceObject(instanceGameObject); + ThrowExceptionIfNotValidPrefabInstanceObject(instanceGameObject, false); var actionName = "Revert Prefab removed component"; var prefabInstanceObject = PrefabUtility.GetPrefabInstanceHandle(instanceGameObject); @@ -1017,7 +1049,8 @@ internal static void HandleApplyMenuItems( string thingThatChanged, Object instanceOrAssetObject, Action addApplyMenuItemAction, - bool defaultOverrideComparedToSomeSources = false) + bool defaultOverrideComparedToSomeSources = false, + bool includeSelfAsTarget = false) { // If thingThatChanged word is empty, apply menu items directly into menu. // Otherwise, insert as sub-menu named after thingThatChanged. @@ -1026,7 +1059,7 @@ internal static void HandleApplyMenuItems( if (thingThatChanged != String.Empty) thingThatChanged += "/"; - List applyTargets = GetApplyTargets(instanceOrAssetObject, defaultOverrideComparedToSomeSources); + List applyTargets = GetApplyTargets(instanceOrAssetObject, defaultOverrideComparedToSomeSources, includeSelfAsTarget); if (applyTargets == null || applyTargets.Count == 0) return; @@ -1148,6 +1181,12 @@ public static Object CreateEmptyPrefab(string path) } public static GameObject SavePrefabAsset(GameObject asset) + { + bool savedSuccesfully; + return SavePrefabAsset(asset, out savedSuccesfully); + } + + public static GameObject SavePrefabAsset(GameObject asset, out bool savedSuccessfully) { if (asset == null) throw new ArgumentNullException("Parameter prefabAssetGameObject is null"); @@ -1167,7 +1206,7 @@ public static GameObject SavePrefabAsset(GameObject asset) if (root != asset) throw new ArgumentException("GameObject to save Prefab from must be a Prefab root"); - return SavePrefabAsset_Internal(root); + return SavePrefabAsset_Internal(root, out savedSuccessfully); } private static void ValidatePath(GameObject instanceRoot, string path) @@ -1620,6 +1659,9 @@ internal static bool HasInvalidComponent(Object gameObjectOrComponent) gameObjectOrComponent = (GameObject)comp.gameObject; } + if (!(gameObjectOrComponent is GameObject)) + return false; + GameObject go; go = (GameObject)gameObjectOrComponent; TransformVisitor transformVisitor = new TransformVisitor(); @@ -1791,7 +1833,7 @@ internal static bool IsObjectOnRootInAsset(Object componentOrGameObject, string return goInAsset.transform.root == goInAsset.transform; } - internal static List GetApplyTargets(Object instanceOrAssetObject, bool defaultOverrideComparedToSomeSources) + internal static List GetApplyTargets(Object instanceOrAssetObject, bool defaultOverrideComparedToSomeSources, bool includeSelfAsTarget = false) { List applyTargets = new List(); @@ -1800,8 +1842,8 @@ internal static List GetApplyTargets(Object instanceOrAssetObject, bool instanceGameObject = (instanceOrAssetObject as Component).gameObject; Object source = instanceOrAssetObject; - if (!EditorUtility.IsPersistent(source)) - source = PrefabUtility.GetCorrespondingObjectFromSource(instanceOrAssetObject); + if (!EditorUtility.IsPersistent(source) || !includeSelfAsTarget) + source = PrefabUtility.GetCorrespondingObjectFromSource(source); if (source == null) return applyTargets; diff --git a/Editor/Mono/PreferencesWindow/PreferencesSettingsProviders.cs b/Editor/Mono/PreferencesWindow/PreferencesSettingsProviders.cs index 0d5fbf3bda..cf66a00cb4 100644 --- a/Editor/Mono/PreferencesWindow/PreferencesSettingsProviders.cs +++ b/Editor/Mono/PreferencesWindow/PreferencesSettingsProviders.cs @@ -9,8 +9,10 @@ using System; using System.IO; using System.Linq; +using Unity.CodeEditor; using UnityEditor.Connect; using UnityEngine.UIElements; +using UnityEngine.TestTools; using UnityEditor.Collaboration; namespace UnityEditor @@ -58,6 +60,7 @@ internal class GeneralProperties public static readonly GUIContent[] editorSkinOptions = { EditorGUIUtility.TrTextContent("Personal"), EditorGUIUtility.TrTextContent("Professional") }; public static readonly GUIContent enableAlphaNumericSorting = EditorGUIUtility.TrTextContent("Enable Alpha Numeric Sorting"); public static readonly GUIContent asyncShaderCompilation = EditorGUIUtility.TrTextContent("Asynchronous Shader Compilation"); + public static readonly GUIContent codeCoverageEnabled = EditorGUIUtility.TrTextContent("Enable Code Coverage", "Check this to enable Code Coverage. Code Coverage lets you see how much of your code is executed when it is run. Note that Code Coverage lowers Editor performance."); } internal class ExternalProperties @@ -95,7 +98,7 @@ internal class TwoDProperties internal class LanguageProperties { - public static readonly GUIContent editorLanguageExperimental = EditorGUIUtility.TrTextContent("Editor Language(Experimental)"); + public static readonly GUIContent editorLanguageExperimental = EditorGUIUtility.TrTextContent("Editor Language (Experimental)"); public static readonly GUIContent editorLanguage = EditorGUIUtility.TrTextContent("Editor language"); } @@ -126,7 +129,6 @@ private struct GICacheSettings private GICacheSettings m_GICacheSettings; private RefString m_ScriptEditorPath = new RefString(""); - private string m_ScriptEditorArgs = ""; private bool m_ExternalEditorSupportsUnityProj; private RefString m_ImageAppPath = new RefString(""); private int m_DiffToolIndex; @@ -141,6 +143,8 @@ private struct GICacheSettings private static SystemLanguage[] m_stableLanguages = { SystemLanguage.English }; private bool m_AllowAlphaNumericHierarchy = false; + private bool m_EnableCodeCoverage = false; + private bool m_EnableCodeCoverageChangedInThisSession = false; private string[] m_ScriptApps; private string[] m_ScriptAppsEditions; @@ -154,6 +158,8 @@ private struct GICacheSettings private const string kRecentScriptAppsKey = "RecentlyUsedScriptApp"; private const string kRecentImageAppsKey = "RecentlyUsedImageApp"; + const string k_UnityGenerateAll = "unity_generate_all_csproj"; + private static readonly string k_ExpressNotSupportedMessage = L10n.Tr( "Unfortunately Visual Studio Express does not allow itself to be controlled by external applications. " + "You can still use it by manually opening the Visual Studio project file, but Unity cannot automatically open files for you when you doubleclick them. " + @@ -305,16 +311,23 @@ private static void OnGUI(string searchContext, Action drawAction) private void ShowExternalApplications(string searchContext) { // Applications - FilePopup(ExternalProperties.externalScriptEditor, m_ScriptEditorPath, ref m_ScriptAppDisplayNames, ref m_ScriptApps, m_ScriptEditorPath, "internal", OnScriptEditorChanged); - - var scriptEditor = GetSelectedScriptEditor(); + FilePopup(ExternalProperties.externalScriptEditor, ScriptEditorUtility.GetExternalScriptEditor(), ref m_ScriptAppDisplayNames, ref m_ScriptApps, m_ScriptEditorPath, CodeEditor.SystemDefaultPath, OnScriptEditorChanged); - if (scriptEditor == ScriptEditorUtility.ScriptEditor.Other) + #pragma warning disable 618 + if (ScriptEditorUtility.GetScriptEditorFromPath(CodeEditor.CurrentEditorInstallation) == ScriptEditorUtility.ScriptEditor.Other) { - string oldEditorArgs = m_ScriptEditorArgs; - m_ScriptEditorArgs = EditorGUILayout.TextField("External Script Editor Args", m_ScriptEditorArgs); - if (oldEditorArgs != m_ScriptEditorArgs) - OnScriptEditorArgsChanged(); + CodeEditor.Editor.Current.OnGUI(); + } + else + { + var prevGenerate = EditorPrefs.GetBool(k_UnityGenerateAll, false); + var generateAll = EditorGUILayout.Toggle("Generate all .csproj files.", prevGenerate); + if (generateAll != prevGenerate) + { + EditorPrefs.SetBool(k_UnityGenerateAll, generateAll); + } + + SyncVS.Synchronizer.GenerateAll(generateAll); } DoUnityProjCheckbox(); @@ -391,6 +404,7 @@ private void DoUnityProjCheckbox() m_ExternalEditorSupportsUnityProj = value; } + #pragma warning disable 618 private ScriptEditorUtility.ScriptEditor GetSelectedScriptEditor() { return ScriptEditorUtility.GetScriptEditorFromPath(m_ScriptEditorPath.str); @@ -398,16 +412,10 @@ private ScriptEditorUtility.ScriptEditor GetSelectedScriptEditor() private void OnScriptEditorChanged() { - ScriptEditorUtility.SetExternalScriptEditor(m_ScriptEditorPath); - m_ScriptEditorArgs = ScriptEditorUtility.GetExternalScriptEditorArgs(); + CodeEditor.SetExternalScriptEditor(m_ScriptEditorPath); UnityEditor.VisualStudioIntegration.UnityVSSupport.ScriptEditorChanged(m_ScriptEditorPath.str); } - private void OnScriptEditorArgsChanged() - { - ScriptEditorUtility.SetExternalScriptEditorArgs(m_ScriptEditorArgs); - } - private void ShowUnityConnectPrefs(string searchContext) { UnityConnectPrefs.ShowPanelPrefUI(); @@ -499,6 +507,14 @@ private void ShowGeneral(string searchContext) InternalEditorUtility.SetGpuDeviceAndRecreateGraphics(newGpuDeviceIndex - 1, m_GpuDevice); } } + + m_EnableCodeCoverage = EditorGUILayout.Toggle(GeneralProperties.codeCoverageEnabled, m_EnableCodeCoverage); + if (m_EnableCodeCoverage != Coverage.enabled) + { + EditorGUILayout.HelpBox((m_EnableCodeCoverage ? "Enabling " : "Disabling ") + "Code Coverage will not take effect until Unity is restarted.", MessageType.Warning); + m_EnableCodeCoverageChangedInThisSession = true; + } + ApplyChangesToPrefs(); if (oldAlphaNumeric != m_AllowAlphaNumericHierarchy) @@ -612,6 +628,7 @@ private void Show2D(string searchContext) private void ShowGICache(string searchContext) { + EditorGUI.BeginChangeCheck(); { // Show Gigabytes to the user. const int kMinSizeInGigabytes = 5; @@ -619,7 +636,6 @@ private void ShowGICache(string searchContext) // Write size in GigaBytes. m_GICacheSettings.m_MaximumSize = EditorGUILayout.IntSlider(GICacheProperties.maxCacheSize, m_GICacheSettings.m_MaximumSize, kMinSizeInGigabytes, kMaxSizeInGigabytes); - WritePreferences(); } GUILayout.BeginHorizontal(); { @@ -650,7 +666,6 @@ private void ShowGICache(string searchContext) if (!string.IsNullOrEmpty(path)) { m_GICacheSettings.m_CachePath = path; - WritePreferences(); } } GUILayout.EndHorizontal(); @@ -678,6 +693,9 @@ private void ShowGICache(string searchContext) GUILayout.Label(GICacheProperties.cacheFolderLocation.text + ":"); GUILayout.Label(UnityEditor.Lightmapping.diskCachePath, Constants.cacheFolderLocation); } + + if (EditorGUI.EndChangeCheck()) + WritePreferences(); } private void ShowLanguage(string searchContext) @@ -744,8 +762,7 @@ private void WriteRecentAppsList(string[] paths, string path, string prefsKey) private void WritePreferences() { - ScriptEditorUtility.SetExternalScriptEditor(m_ScriptEditorPath); - ScriptEditorUtility.SetExternalScriptEditorArgs(m_ScriptEditorArgs); + CodeEditor.SetExternalScriptEditor(m_ScriptEditorPath); EditorPrefs.SetBool("kExternalEditorSupportsUnityProj", m_ExternalEditorSupportsUnityProj); EditorPrefs.SetString("kImagesDefaultApp", m_ImageAppPath); @@ -782,6 +799,14 @@ private void WritePreferences() EditorPrefs.SetString("Editor.kEditorLocale", m_SelectedLanguage); EditorPrefs.SetBool("AllowAlphaNumericHierarchy", m_AllowAlphaNumericHierarchy); + EditorPrefs.SetBool("CodeCoverageEnabled", m_EnableCodeCoverage); + + if (m_EnableCodeCoverageChangedInThisSession) + { + EditorPrefs.SetBool("CodeCoverageEnabledMessageShown", false); + m_EnableCodeCoverageChangedInThisSession = false; + } + EditorPrefs.SetString("GpuDeviceName", m_GpuDevice); EditorPrefs.SetBool("GICacheEnableCustomPath", m_GICacheSettings.m_EnableCustomPath); @@ -812,12 +837,11 @@ static private string GetProgramFilesFolder() private void ReadPreferences() { m_ScriptEditorPath.str = ScriptEditorUtility.GetExternalScriptEditor(); - m_ScriptEditorArgs = ScriptEditorUtility.GetExternalScriptEditorArgs(); m_ExternalEditorSupportsUnityProj = EditorPrefs.GetBool("kExternalEditorSupportsUnityProj", false); m_ImageAppPath.str = EditorPrefs.GetString("kImagesDefaultApp"); - m_ScriptApps = BuildAppPathList(m_ScriptEditorPath, kRecentScriptAppsKey, "internal"); + m_ScriptApps = BuildAppPathList(m_ScriptEditorPath, kRecentScriptAppsKey, CodeEditor.SystemDefaultPath); m_ScriptAppsEditions = new string[m_ScriptApps.Length]; if (Application.platform == RuntimePlatform.WindowsEditor) @@ -838,7 +862,12 @@ private void ReadPreferences() } } - var foundScriptEditorPaths = ScriptEditorUtility.GetFoundScriptEditorPaths(Application.platform); + var foundScriptEditorPaths = CodeEditor.Editor.GetFoundScriptEditorPaths(); + if (Application.platform == RuntimePlatform.OSXEditor) + { + CodeEditor.AddIfPathExists("Visual Studio", "/Applications/Visual Studio.app", foundScriptEditorPaths); + CodeEditor.AddIfPathExists("Visual Studio (Preview)", "/Applications/Visual Studio (Preview).app", foundScriptEditorPaths); + } foreach (var scriptEditorPath in foundScriptEditorPaths.Keys) { @@ -889,6 +918,7 @@ private void ReadPreferences() m_EnableEditorLocalization = EditorPrefs.GetBool("Editor.kEnableEditorLocalization", true); m_SelectedLanguage = EditorPrefs.GetString("Editor.kEditorLocale", LocalizationDatabase.GetDefaultEditorLanguage().ToString()); m_AllowAlphaNumericHierarchy = EditorPrefs.GetBool("AllowAlphaNumericHierarchy", false); + m_EnableCodeCoverage = EditorPrefs.GetBool("CodeCoverageEnabled", false); m_CompressAssetsOnImport = Unsupported.GetApplicationSettingCompressAssetsOnImport(); m_GpuDevice = EditorPrefs.GetString("GpuDeviceName"); @@ -1002,7 +1032,7 @@ private string[] BuildFriendlyAppNameList(string[] appPathList, string[] appEdit { var appPath = appPathList[i]; - if (appPath == "internal" || appPath == "") // use built-in + if (appPath == CodeEditor.SystemDefaultPath) // use built-in list.Add(defaultBuiltIn); else { diff --git a/Editor/Mono/ProjectWindow/ProjectWindowUtil.cs b/Editor/Mono/ProjectWindow/ProjectWindowUtil.cs index dd858afe22..6aa10d95f0 100644 --- a/Editor/Mono/ProjectWindow/ProjectWindowUtil.cs +++ b/Editor/Mono/ProjectWindow/ProjectWindowUtil.cs @@ -329,9 +329,11 @@ public static void CreateScriptAssetFromTemplateFile(string templatePath, string icon = EditorGUIUtility.IconContent().image as Texture2D; break; case ".asmdef": - case ".asmref": icon = EditorGUIUtility.IconContent().image as Texture2D; break; + case ".asmref": + icon = EditorGUIUtility.IconContent().image as Texture2D; + break; default: icon = EditorGUIUtility.IconContent().image as Texture2D; break; @@ -747,9 +749,9 @@ internal static bool DeleteAssets(List instanceIDs, bool askIfSure) { string title; if (paths.Count > 1) - title = L10n.Tr("Delete selected assets ?"); + title = L10n.Tr("Delete selected assets?"); else - title = L10n.Tr("Delete selected asset ?"); + title = L10n.Tr("Delete selected asset?"); int maxCount = 3; var infotext = new StringBuilder(); diff --git a/Editor/Mono/ProjectWindow/SearchableEditorWindow.cs b/Editor/Mono/ProjectWindow/SearchableEditorWindow.cs index 26c2dd57d6..1442c42159 100644 --- a/Editor/Mono/ProjectWindow/SearchableEditorWindow.cs +++ b/Editor/Mono/ProjectWindow/SearchableEditorWindow.cs @@ -145,8 +145,8 @@ internal static void SearchForReferencesToInstanceID(int instanceID) { string searchFilter; - // only main assets have unique paths (remove "Assets" to make string simpler) - string path = AssetDatabase.GetAssetPath(instanceID).Substring(7); + // Don't remove "Assets" prefix, we need to support Packages as well (https://fogbugz.unity3d.com/f/cases/1161019/) + string path = AssetDatabase.GetAssetPath(instanceID); if (path.IndexOf(' ') != -1) path = '"' + path + '"'; diff --git a/Editor/Mono/SavedGUIState.bindings.cs b/Editor/Mono/SavedGUIState.bindings.cs index 13537fdf5b..f1a57bac98 100644 --- a/Editor/Mono/SavedGUIState.bindings.cs +++ b/Editor/Mono/SavedGUIState.bindings.cs @@ -3,8 +3,10 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; +using System.Collections; using UnityEngine; using UnityEngine.Bindings; +using UnityEngineInternal; namespace UnityEditor { @@ -17,6 +19,7 @@ internal struct SavedGUIState internal Rect renderManagerRect; internal GUISkin skin; internal int instanceID; + internal GenericStack scrollViewStates; static private extern void Internal_SetupSavedGUIState(out IntPtr state, out Vector2 screenManagerSize); @@ -32,6 +35,12 @@ static internal SavedGUIState Create() state.skin = GUI.skin; state.layoutCache = new GUILayoutUtility.LayoutCache(GUILayoutUtility.current); state.instanceID = GUIUtility.s_OriginalID; + if (GUI.scrollViewStates.Count != 0) + { + state.scrollViewStates = GUI.scrollViewStates; + GUI.scrollViewStates = new GenericStack(); + } + Internal_SetupSavedGUIState(out state.guiState, out state.screenManagerSize); } return state; @@ -44,6 +53,12 @@ internal void ApplyAndForget() GUILayoutUtility.current = layoutCache; GUI.skin = skin; GUIUtility.s_OriginalID = instanceID; + + if (scrollViewStates != null) + { + GUI.scrollViewStates = scrollViewStates; + } + Internal_ApplySavedGUIState(guiState, screenManagerSize); GUIClip.Reapply(); } diff --git a/Editor/Mono/SceneHierarchy.cs b/Editor/Mono/SceneHierarchy.cs index 7cd7a914d2..085b337429 100644 --- a/Editor/Mono/SceneHierarchy.cs +++ b/Editor/Mono/SceneHierarchy.cs @@ -766,9 +766,14 @@ void OnEvent() // So the background doesn't stop if we don't have enough item to fill the entire tree view rect, we draw the background in the unused space. private void DoSceneVisibilityBackgroundOverflow(float reservedFooterSpace) { - Vector2 sizeTaken = treeView.gui.GetTotalSize(); + float treeViewHeight = treeView.gui.GetTotalSize().y; Rect rectWithNoRows = treeViewRect; - rectWithNoRows.yMin += sizeTaken.y; + + //If the tree view already covers the entire rect, we don't need to fill the overflow + if (rectWithNoRows.height <= treeViewHeight) + return; + + rectWithNoRows.yMin += treeViewHeight; rectWithNoRows.height -= reservedFooterSpace; SceneVisibilityHierarchyGUI.DrawBackground(rectWithNoRows); @@ -994,7 +999,7 @@ void CreateGameObjectContextClick(GenericMenu menu, int contextClickedItemID) menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Rename")); menu.AddItem(EditorGUIUtility.TrTextContent("Duplicate"), false, DuplicateGO); - if (GetIsCustomParentSelected() || GetIsNotEditable()) + if (GetIsCustomParentSelected()) menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Delete")); else menu.AddItem(EditorGUIUtility.TrTextContent("Delete"), false, DeleteGO); @@ -1058,7 +1063,7 @@ void CreateGameObjectContextClick(GenericMenu menu, int contextClickedItemID) info.instanceObject = go; info.assetPath = AssetDatabase.GetAssetPath(sourceGo); GameObject rootGo = PrefabUtility.GetRootGameObject(sourceGo); - if (!PrefabUtility.IsPartOfPrefabThatCanBeAppliedTo(rootGo)) + if (!PrefabUtility.IsPartOfPrefabThatCanBeAppliedTo(rootGo) || EditorUtility.IsPersistent(parentTransform)) menu.AddDisabledItem(menuItemContent); else menu.AddItem(menuItemContent, false, TargetChoiceHandler.ApplyPrefabAddedGameObject, info); diff --git a/Editor/Mono/SceneHierarchyStageHandling.cs b/Editor/Mono/SceneHierarchyStageHandling.cs index 6ab5d6fb7c..f1eee9c597 100644 --- a/Editor/Mono/SceneHierarchyStageHandling.cs +++ b/Editor/Mono/SceneHierarchyStageHandling.cs @@ -46,6 +46,7 @@ public void OnEnable() StageNavigationManager.instance.prefabStageReloaded += OnPrefabStageReloaded; StageNavigationManager.instance.prefabStageToBeDestroyed += OnPrefabStageBeingDestroyed; PrefabStage.prefabIconChanged += OnPrefabStageIconChanged; + PrefabStage.prefabRootTransformChanged += OnPrefabStageRootTransformChanged; // To support expanded state of new unsaved GameObject in Prefab Mode across domain reloading we do not load the // last saved expanded state here but instead rely on the fact that the Hierarchy serializes its own expanded state already. @@ -61,6 +62,7 @@ public void OnDisable() StageNavigationManager.instance.prefabStageReloaded -= OnPrefabStageReloaded; StageNavigationManager.instance.prefabStageToBeDestroyed -= OnPrefabStageBeingDestroyed; PrefabStage.prefabIconChanged -= OnPrefabStageIconChanged; + PrefabStage.prefabRootTransformChanged -= OnPrefabStageRootTransformChanged; } void OnPrefabStageBeingDestroyed(StageNavigationItem prefabStage) @@ -220,6 +222,11 @@ void OnPrefabStageIconChanged(PrefabStage prefabStage) m_PrefabHeaderContent.image = prefabStage.prefabFileIcon; } + void OnPrefabStageRootTransformChanged(PrefabStage prefabStage) + { + m_SceneHierarchy.customParentForNewGameObjects = prefabStage.prefabContentsRoot.transform; + } + void CachePrefabHeaderText(StageNavigationItem stage) { if (!stage.isPrefabStage) @@ -310,7 +317,11 @@ public void PrefabStageHeaderGUI(Rect rect) overlayRect.width = 16; overlayRect.y += (overlayRect.height - 16) / 2; overlayRect.height = 16; - AssetsTreeViewGUI.OnIconOverlayGUI(AssetDatabase.LoadMainAssetAtPath(currentItem.prefabAssetPath).GetInstanceID(), overlayRect, true); + + // The source prefab can have been deleted while open in Prefab Mode so the library object can be null here (case 1086613) + var prefabAsset = AssetDatabase.LoadMainAssetAtPath(currentItem.prefabAssetPath); + if (prefabAsset != null) + AssetsTreeViewGUI.OnIconOverlayGUI(prefabAsset.GetInstanceID(), overlayRect, true); } } } diff --git a/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStage.cs b/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStage.cs index 169373e23b..33258aee8b 100644 --- a/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStage.cs +++ b/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStage.cs @@ -26,6 +26,7 @@ public class PrefabStage public static event Action prefabSaving; public static event Action prefabSaved; internal static event Action prefabIconChanged; + internal static event Action prefabRootTransformChanged; internal static event Action prefabStageSavedAsNewPrefab; GameObject m_PrefabContentsRoot; // Prefab asset being edited @@ -39,6 +40,7 @@ public class PrefabStage Texture2D m_PrefabFileIcon; bool m_TemporarilyDisableAutoSave; float m_LastSavingDuration = 0f; + Transform m_LastRootTransform; const float kDurationBeforeShowingSavingBadge = 1.0f; bool m_AnalyticsDidUserModify; @@ -131,6 +133,12 @@ internal PrefabStage() internal bool LoadStage(string prefabPath) { + if (!File.Exists(prefabPath)) + { + Debug.LogError("LoadStage with an invalid path: Prefab file not found " + prefabPath); + return false; + } + if (isValid) Cleanup(); @@ -146,6 +154,7 @@ internal bool LoadStage(string prefabPath) { PrefabStageUtility.HandleReparentingIfNeeded(m_PrefabContentsRoot, isUIPrefab); m_PrefabFileIcon = DeterminePrefabFileIconFromInstanceRootGameObject(); + m_LastRootTransform = m_PrefabContentsRoot.transform; m_InitialSceneDirtyID = m_PreviewScene.dirtyID; UpdateEnvironmentHideFlags(); } @@ -239,6 +248,15 @@ internal void Update() HandlePrefabChangedOnDisk(); DetectSceneDirtinessChange(); DetectPrefabFileIconChange(); + DetectPrefabRootTransformChange(); + } + + void DetectPrefabRootTransformChange() + { + var currentTransform = m_PrefabContentsRoot.transform; + if (currentTransform != m_LastRootTransform) + prefabRootTransformChanged?.Invoke(this); + m_LastRootTransform = currentTransform; } void DetectPrefabFileIconChange() @@ -310,6 +328,10 @@ void HandlePrefabChangedOnDisk() if (m_PrefabWasChangedOnDisk) { m_PrefabWasChangedOnDisk = false; + + if (!File.Exists(m_PrefabAssetPath)) + return; + if (HasSceneBeenModified()) { var title = L10n.Tr("Prefab Has Been Changed on Disk"); diff --git a/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStageUtility.cs b/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStageUtility.cs index 61f675e3db..e3afdfbb2f 100644 --- a/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStageUtility.cs +++ b/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStageUtility.cs @@ -194,6 +194,9 @@ static GameObject FindPrefabRoot(string prefabAssetPath, GameObject[] environmen // Fast path (most common): check all roots first foreach (var prefabRoot in rootsAfterLoadingPrefab) { + if (prefabRoot == null) + continue; + UInt64 id = GetPrefabOrVariantFileID(prefabRoot); if (id == prefabAssetRootFileID) return prefabRoot; @@ -202,6 +205,9 @@ static GameObject FindPrefabRoot(string prefabAssetPath, GameObject[] environmen // If not found in list of roots then check descendants foreach (var root in rootsAfterLoadingPrefab) { + if (root == null) + continue; + var prefabRoot = FindFirstGameObjectThatMatchesFileID(root.transform, prefabAssetRootFileID); if (prefabRoot != null) return prefabRoot; @@ -305,31 +311,31 @@ static void AppendEnvironmentName(Transform transform, object userData) static Scene CreateDefaultPreviewScene() { Scene previewScene = EditorSceneManager.NewPreviewScene(); - Unsupported.SetOverrideRenderSettings(previewScene); // Setup default render settings for this preview scene + Unsupported.SetOverrideLightingSettings(previewScene); UnityEngine.RenderSettings.defaultReflectionMode = UnityEngine.Rendering.DefaultReflectionMode.Custom; - UnityEngine.RenderSettings.customReflection = GetDefaultReflection(); // ensure chrome materials do not render balck - UnityEngine.RenderSettings.skybox = null; // do not use skybox for the default previewscene, we want the flat Prefab Mode background color to let it stand out from normal scenes - UnityEngine.RenderSettings.ambientMode = AmbientMode.Trilight; // do not use skybox ambient but simple trilight ambient for simplicity - Unsupported.RestoreOverrideRenderSettings(); + UnityEngine.RenderSettings.customReflection = GetDefaultReflection(); // ensure chrome materials do not render black + UnityEngine.RenderSettings.skybox = AssetDatabase.GetBuiltinExtraResource("Default-Skybox.mat") as Material; + UnityEngine.RenderSettings.ambientMode = AmbientMode.Skybox; + UnityEditorInternal.InternalEditorUtility.CalculateAmbientProbeFromSkybox(); + Unsupported.RestoreOverrideLightingSettings(); return previewScene; } - static Cubemap s_DefaultHDRI; + static Cubemap s_DefaultReflection; static Cubemap GetDefaultReflection() { - if (s_DefaultHDRI == null) + const string path = "PrefabMode/DefaultReflectionForPrefabMode.exr"; + if (s_DefaultReflection == null) { - s_DefaultHDRI = EditorGUIUtility.Load("LookDevView/DefaultHDRI.exr") as Cubemap; - if (s_DefaultHDRI == null) - s_DefaultHDRI = EditorGUIUtility.Load("LookDevView/DefaultHDRI.asset") as Cubemap; + s_DefaultReflection = EditorGUIUtility.Load(path) as Cubemap; } - if (s_DefaultHDRI == null) - Debug.LogError("Could not find DefaultHDRI"); - return s_DefaultHDRI; + if (s_DefaultReflection == null) + Debug.LogError("Could not find: " + path); + return s_DefaultReflection; } internal static void DestroyPreviewScene(Scene previewScene) @@ -359,7 +365,12 @@ internal static bool IsUIPrefab(string prefabAssetPath) if (root == null) return false; - return root.GetComponent() != null && root.GetComponentInChildren(true) != null; + // In principle, RectTransforms can be used for other things than UI, + // so only treat as UI Prefab if it has both a RectTransform on the root + // AND either a Canvas on the root or a CanvasRenderer somewhere in the hierarchy. + bool rectTransformOnRoot = root.GetComponent() != null; + bool uiSpecificComponentPresent = (root.GetComponent() != null || root.GetComponentInChildren(true) != null); + return rectTransformOnRoot && uiSpecificComponentPresent; } static void HandleUIReparentingIfNeeded(GameObject instanceRoot) diff --git a/Editor/Mono/SceneManagement/StageManager/Stage.cs b/Editor/Mono/SceneManagement/StageManager/Stage.cs index 0ac2f887fa..b49d72e5ba 100644 --- a/Editor/Mono/SceneManagement/StageManager/Stage.cs +++ b/Editor/Mono/SceneManagement/StageManager/Stage.cs @@ -40,7 +40,7 @@ public T FindComponentOfType() where T : Component for (int i = 0; i < components.Length; i++) { T obj = components[i]; - if (!EditorSceneManager.IsPreviewScene(obj.gameObject.scene)) + if (!EditorUtility.IsPersistent(obj) && !EditorSceneManager.IsPreviewScene(obj.gameObject.scene)) return obj; } } @@ -68,7 +68,7 @@ public T[] FindComponentsOfType() where T : Component for (int i = 0; i < components.Length; i++) { T obj = components[i]; - if (!EditorSceneManager.IsPreviewScene(obj.gameObject.scene)) + if (!EditorUtility.IsPersistent(obj) && !EditorSceneManager.IsPreviewScene(obj.gameObject.scene)) componentList.Add(obj); } } diff --git a/Editor/Mono/SceneManagement/StageManager/StageNavigationManager.cs b/Editor/Mono/SceneManagement/StageManager/StageNavigationManager.cs index 832d7aaa0a..baa7f435bf 100644 --- a/Editor/Mono/SceneManagement/StageManager/StageNavigationManager.cs +++ b/Editor/Mono/SceneManagement/StageManager/StageNavigationManager.cs @@ -612,7 +612,7 @@ public void ChangingStageStarted(StageNavigationItem previousStageItem) m_EventData = new EventData(); m_EventData.existingStage = GetStageType(previousStageItem); m_EventData.existingBreadcrumbCount = StageNavigationManager.instance.stageHistory.Length; - if (previousStageItem.isPrefabStage) + if (previousStageItem.prefabStage != null) { m_EventData.didUserModify = previousStageItem.prefabStage.analyticsDidUserModify; m_EventData.didUserSave = previousStageItem.prefabStage.analyticsDidUserSave; diff --git a/Editor/Mono/SceneManagement/StageManager/StageUtility.cs b/Editor/Mono/SceneManagement/StageManager/StageUtility.cs index e24a62f8a8..f6b1f3de1f 100644 --- a/Editor/Mono/SceneManagement/StageManager/StageUtility.cs +++ b/Editor/Mono/SceneManagement/StageManager/StageUtility.cs @@ -13,7 +13,7 @@ namespace UnityEditor.SceneManagement { public static partial class StageUtility { - [Shortcut("Stage/Go Back", KeyCode.H)] + [Shortcut("Stage/Go Back")] static void GoBackShortcut() { StageUtility.GoBackToPreviousStage(); diff --git a/Editor/Mono/SceneModeWindows/LightingWindowBakeSettings.cs b/Editor/Mono/SceneModeWindows/LightingWindowBakeSettings.cs index b5f244b5a9..493b46d2de 100644 --- a/Editor/Mono/SceneModeWindows/LightingWindowBakeSettings.cs +++ b/Editor/Mono/SceneModeWindows/LightingWindowBakeSettings.cs @@ -825,18 +825,18 @@ static class Styles public static readonly GUIContent FinalGatherFiltering = EditorGUIUtility.TrTextContent("Denoising", "Controls whether a denoising filter is applied to the final gather output."); public static readonly GUIContent SubtractiveShadowColor = EditorGUIUtility.TrTextContent("Realtime Shadow Color", "The color used for mixing realtime shadows with baked lightmaps in Subtractive lighting mode. The color defines the darkest point of the realtime shadow."); public static readonly GUIContent MixedLightMode = EditorGUIUtility.TrTextContent("Lighting Mode", "Specifies which Scene lighting mode will be used for all Mixed lights in the Scene. Options are Baked Indirect, Shadowmask and Subtractive."); - public static readonly GUIContent UseRealtimeGI = EditorGUIUtility.TrTextContent("Realtime Global Illumination", "Controls whether Realtime lights in the Scene contribute indirect light. If enabled, Realtime lights contribute both direct and indirect light. If disabled, Realtime lights only contribute direct light. This can be disabled on a per-light basis in the light component Inspector by setting Indirect Multiplier to 0."); + public static readonly GUIContent UseRealtimeGI = EditorGUIUtility.TrTextContent("Realtime Global Illumination (Deprecated)", "Enlighten is entering deprecation. Please ensure that your project will not require support for Enlighten beyond the deprecation date."); public static readonly GUIContent BakedGIDisabledInfo = EditorGUIUtility.TrTextContent("All Baked and Mixed lights in the Scene are currently being overridden to Realtime light modes. Enable Baked Global Illumination to allow the use of Baked and Mixed light modes."); public static readonly GUIContent BakeBackend = EditorGUIUtility.TrTextContent("Lightmapper", "Specifies which baking system will be used to generate baked lightmaps."); - //public static readonly GUIContent PVRSampling = EditorGUIUtility.TrTextContent("Sampling", "How to sample the lightmaps. Auto and adaptive automatically tests for convergence. Auto uses a maximum of 16K samples. Adaptive uses a configurable maximum number of samples. Fixed always uses the set number of samples and does not test for convergence."); + //public static readonly GUIContent PVRSampling = EditorGUIUtility.TrTextContent("Sampling", "How to sample the lightmaps. Auto and adaptive automatically test for convergence. Auto uses a maximum of 16K samples. Adaptive uses a configurable maximum number of samples. Fixed always uses the set number of samples and does not test for convergence."); //public static readonly GUIContent PVRDirectSampleCountAdaptive = EditorGUIUtility.TrTextContent("Max Direct Samples", "Maximum number of samples to use for direct lighting."); public static readonly GUIContent PVRDirectSampleCount = EditorGUIUtility.TrTextContent("Direct Samples", "Controls the number of samples the lightmapper will use for direct lighting calculations. Increasing this value may improve the quality of lightmaps but increases the time required for baking to complete."); //public static readonly GUIContent PVRSampleCountAdaptive = EditorGUIUtility.TrTextContent("Max Indirect Samples", "Maximum number of samples to use for indirect lighting."); public static readonly GUIContent PVRIndirectSampleCount = EditorGUIUtility.TrTextContent("Indirect Samples", "Controls the number of samples the lightmapper will use for indirect lighting calculations. Increasing this value may improve the quality of lightmaps but increases the time required for baking to complete."); public static readonly GUIContent PVRBounces = EditorGUIUtility.TrTextContent("Bounces", "Controls the maximum number of bounces the lightmapper will compute for indirect light."); - public static readonly GUIContent DenoisingWarningDirect = EditorGUIUtility.TrTextContent("Direct Denoiser", "Your hardware doesn’t support denoising. To see minimum requirements, read the documentation."); - public static readonly GUIContent DenoisingWarningIndirect = EditorGUIUtility.TrTextContent("Indirect Denoiser", "Your hardware doesn’t support denoising. To see minimum requirements, read the documentation."); - public static readonly GUIContent DenoisingWarningAO = EditorGUIUtility.TrTextContent("Ambient Occlusion Denoiser", "Your hardware doesn’t support denoising. To see minimum requirements, read the documentation."); + public static readonly GUIContent DenoisingWarningDirect = EditorGUIUtility.TrTextContent("Direct Denoiser", "Your hardware doesn't support denoising. To see minimum requirements, read the documentation."); + public static readonly GUIContent DenoisingWarningIndirect = EditorGUIUtility.TrTextContent("Indirect Denoiser", "Your hardware doesn't support denoising. To see minimum requirements, read the documentation."); + public static readonly GUIContent DenoisingWarningAO = EditorGUIUtility.TrTextContent("Ambient Occlusion Denoiser", "Your hardware doesn't support denoising. To see minimum requirements, read the documentation."); public static readonly GUIContent PVRDenoiserTypeDirect = EditorGUIUtility.TrTextContent("Direct Denoiser", "Specifies the type of denoiser used to reduce noise for direct lights."); public static readonly GUIContent PVRDenoiserTypeIndirect = EditorGUIUtility.TrTextContent("Indirect Denoiser", "Specifies the type of denoiser used to reduce noise for indirect lights."); public static readonly GUIContent PVRDenoiserTypeAO = EditorGUIUtility.TrTextContent("Ambient Occlusion Denoiser", "Specifies the type of denoiser used to reduce noise for ambient occlusion."); @@ -851,7 +851,7 @@ static class Styles public static readonly GUIContent PVRFilteringAtrousPositionSigmaIndirect = EditorGUIUtility.TrTextContent("Sigma", "Controls the threshold of the filter for indirect light stored in the lightmap. A higher value increases the threshold, which reduces noise in the direct layer of the lightmap. Too high of a value can cause a loss of detail in the lightmap."); public static readonly GUIContent PVRFilteringAtrousPositionSigmaAO = EditorGUIUtility.TrTextContent("Sigma", "Controls the threshold of the filter for ambient occlusion stored in the lightmap. A higher value increases the threshold, which reduces noise in the direct layer of the lightmap. Too high of a value can cause a loss of detail in the lightmap."); public static readonly GUIContent PVRCulling = EditorGUIUtility.TrTextContent("Prioritize View", "Specifies whether the lightmapper should prioritize baking texels within the scene view. When disabled, objects outside the scene view will have the same priority as those in the scene view."); - public static readonly GUIContent PVREnvironmentMIS = EditorGUIUtility.TrTextContent("Multiple Importance Sampling", "Specifies whether to use multiple importance sampling for sampling the environment. This will generally lead to faster convergence when generating lightmaps, but can lead to noisier results in certain low frequency environments."); + public static readonly GUIContent PVREnvironmentMIS = EditorGUIUtility.TrTextContent("Multiple Importance Sampling", "Specifies whether to use multiple importance sampling for sampling the environment. This will generally lead to faster convergence when generating lightmaps but can lead to noisier results in certain low frequency environments."); public static readonly GUIContent PVREnvironmentSampleCount = EditorGUIUtility.TrTextContent("Environment Samples", "Controls the number of samples the lightmapper will use for environment lighting calculations. Increasing this value may improve the quality of lightmaps but increases the time required for baking to complete."); // TODO(RadeonRays): Used for hiding A-trous filtering option until it is implemented. public static readonly GUIContent[] GPUFilterOptions = new[] { EditorGUIUtility.TrTextContent("Gaussian"), EditorGUIUtility.TrTextContent("None") }; diff --git a/Editor/Mono/SceneModeWindows/LightmapPreviewWindow.cs b/Editor/Mono/SceneModeWindows/LightmapPreviewWindow.cs index 0993ed453e..7190dc4305 100644 --- a/Editor/Mono/SceneModeWindows/LightmapPreviewWindow.cs +++ b/Editor/Mono/SceneModeWindows/LightmapPreviewWindow.cs @@ -95,7 +95,7 @@ static class Styles public static readonly GUIContent TextureNotAvailableRealtime = EditorGUIUtility.TrTextContent("The texture is not available at the moment."); public static readonly GUIContent TextureNotAvailableBaked = EditorGUIUtility.TrTextContent("The texture is not available at the moment.\nPlease try to rebake the current scene or turn on Auto, and make sure that this object is set to 'Contribute Global Illumination' if it's meant to be baked."); public static readonly GUIContent TextureNotAvailableBakedShadowmask = EditorGUIUtility.TrTextContent("The texture is not available at the moment.\nPlease make sure that Mixed Lights affect this GameObject and that it is set to 'Contribute Global Illumination'."); - public static readonly GUIContent TextureNotAvailableBakedAlbedoEmissive = EditorGUIUtility.TrTextContent("The texture is not an index based texture and is not available when using Progressive.\nPlease go to the instance you wish to debug, and select the lightmap on the Mesh Renderer."); + public static readonly GUIContent TextureNotAvailableBakedAlbedoEmissive = EditorGUIUtility.TrTextContent("The texture is not an index-based texture and is not available when using Progressive.\nPlease go to the instance you wish to debug, and select the lightmap on the Mesh Renderer."); public static readonly GUIContent TextureLoading = EditorGUIUtility.TrTextContent("Loading..."); public static readonly GUIContent UVOverlayIcon = EditorGUIUtility.TrIconContent("ToggleUVOverlay", "Toggles the UV Overlay for all the objects in the lightmap. The currently selected object will be highlighted. "); public static readonly GUIContent ExposureIcon = EditorGUIUtility.TrIconContent("SceneViewLighting", "Controls the number of stops to over or under expose the lightmap."); @@ -140,7 +140,7 @@ private string lightmapTitle private float exposure { - get { return SelectedTextureNeedExposureControl() ? m_ExposureSliderValue : 0.0f; } + get { return SelectedTextureTypeNeedExposureControl() ? m_ExposureSliderValue : 0.0f; } } public static void CreateLightmapPreviewWindow(int lightmapId, bool realtimeLightmap, bool indexBased) @@ -187,7 +187,7 @@ void OnGUI() GUILayout.Label(lightmapTitle, "preToolbar2"); GUILayout.FlexibleSpace(); - PreviewSettings(); + DrawPreviewSettings(); EditorGUILayout.EndHorizontal(); @@ -203,42 +203,9 @@ void OnGUI() EditorGUILayout.EndVertical(); } - private void UpdateActiveGameObjectSelection() + private void DrawPreviewSettings() { - MeshRenderer renderer; - Terrain terrain = null; - - // if the active object in the selection is a renderer or a terrain, we're interested in it's lightmapIndex - if (Selection.activeGameObject == null || - ((renderer = Selection.activeGameObject.GetComponent()) == null && - (terrain = Selection.activeGameObject.GetComponent()) == null)) - { - m_ActiveGameObjectLightmapIndex = -1; - m_ActiveGameObjectInstanceId = -1; - m_ActiveGameObjectTextureHash = new Hash128(); - return; - } - if (isRealtimeLightmap) - { - Hash128 inputSystemHash; - if ((renderer != null && LightmapEditorSettings.GetInputSystemHash(renderer.GetInstanceID(), out inputSystemHash)) - || (terrain != null && LightmapEditorSettings.GetInputSystemHash(terrain.GetInstanceID(), out inputSystemHash))) - { - m_ActiveGameObjectTextureHash = inputSystemHash; - } - else - m_ActiveGameObjectTextureHash = new Hash128(); - } - else - { - m_ActiveGameObjectLightmapIndex = renderer != null ? renderer.lightmapIndex : terrain.lightmapIndex; - m_ActiveGameObjectInstanceId = renderer != null ? renderer.GetInstanceID() : terrain.GetInstanceID(); - } - } - - private void PreviewSettings() - { - using (new EditorGUI.DisabledScope(!SelectedTextureNeedExposureControl())) + using (new EditorGUI.DisabledScope(!SelectedTextureTypeNeedExposureControl())) { float labelWidth = EditorGUIUtility.labelWidth; EditorGUIUtility.labelWidth = 20; @@ -256,7 +223,7 @@ private void PreviewSettings() m_ShowUVOverlay = GUILayout.Toggle(m_ShowUVOverlay, Styles.UVOverlayIcon, "preButton"); - Rect dropRect = GUILayoutUtility.GetRect(14, 160, EditorGUI.kWindowToolbarHeight, EditorGUI.kWindowToolbarHeight); + Rect dropRect = GUILayoutUtility.GetRect(14, 170, EditorGUI.kWindowToolbarHeight, EditorGUI.kWindowToolbarHeight); GUIContent[] options = isRealtimeLightmap ? Styles.RealtimePreviewTextureOptions : Styles.BakedPreviewTextureOptions; GITextureType[] types = isRealtimeLightmap ? kRealtimePreviewTextureTypes : kBakedPreviewTextureTypes; @@ -345,7 +312,7 @@ private void DrawPreview(Rect r) case EventType.ValidateCommand: case EventType.ExecuteCommand: - if (Event.current.commandName == EventCommandNames.FrameSelected && IsSelectedObjectInLightmap(textureType)) + if (Event.current.commandName == EventCommandNames.FrameSelected && IsActiveGameObjectInLightmap(textureType)) { // There are instance based baked textures where we don't get any STs and can't do the framing if (!isRealtimeLightmap && !LightmapVisualizationUtility.IsAtlasTextureType(textureType)) @@ -402,7 +369,7 @@ private void DrawPreview(Rect r) texture.filterMode = FilterMode.Point; LightmapVisualizationUtility.DrawTextureWithUVOverlay(texture, - (m_ShowUVOverlay && IsSelectedObjectInLightmap(textureType)) ? Selection.activeGameObject : null, + (m_ShowUVOverlay && IsActiveGameObjectInLightmap(textureType)) ? Selection.activeGameObject : null, m_ShowUVOverlay ? m_CachedTextureObjects : new GameObject[] {}, drawableArea, textureRect, textureType, exposure); texture.filterMode = prevMode; } @@ -420,17 +387,6 @@ private void SelectPreviewTextureIndex(object textureOption) m_SelectedPreviewTextureOptionIndex = Array.IndexOf(options, textureOption); } - private bool IsSelectedObjectInLightmap(GITextureType textureType) - { - if (isRealtimeLightmap) - return (m_ActiveGameObjectTextureHash == m_RealtimeTextureHash); - - if (LightmapVisualizationUtility.IsAtlasTextureType(textureType)) - return (m_ActiveGameObjectLightmapIndex == m_LightmapIndex); - - return (m_ActiveGameObjectInstanceId == m_InstanceID); - } - private GITextureType GetSelectedTextureType() { GUIContent[] options = isRealtimeLightmap ? Styles.RealtimePreviewTextureOptions : Styles.BakedPreviewTextureOptions; @@ -444,7 +400,7 @@ private GITextureType GetSelectedTextureType() return types[m_SelectedPreviewTextureOptionIndex]; } - private bool SelectedTextureNeedExposureControl() + private bool SelectedTextureTypeNeedExposureControl() { var textureType = GetSelectedTextureType(); @@ -453,6 +409,52 @@ private bool SelectedTextureNeedExposureControl() textureType == GITextureType.Emissive || textureType == GITextureType.Irradiance; } + private bool IsActiveGameObjectInLightmap(GITextureType textureType) + { + if (isRealtimeLightmap) + return (m_ActiveGameObjectTextureHash == m_RealtimeTextureHash); + + if (LightmapVisualizationUtility.IsAtlasTextureType(textureType)) + return (m_ActiveGameObjectLightmapIndex == m_LightmapIndex); + + return (m_ActiveGameObjectInstanceId == m_InstanceID); + } + + private void UpdateActiveGameObjectSelection() + { + MeshRenderer renderer = null; + Terrain terrain = null; + + // if the selected active object (also active in the hierarchy) is a renderer or a terrain, we check its index etc. + // otherwise bail + if (Selection.activeGameObject == null || !Selection.activeGameObject.activeInHierarchy || + (!Selection.activeGameObject.TryGetComponent(out renderer) && + !Selection.activeGameObject.TryGetComponent(out terrain))) + { + m_ActiveGameObjectLightmapIndex = -1; + m_ActiveGameObjectInstanceId = -1; + m_ActiveGameObjectTextureHash = new Hash128(); + return; + } + + if (isRealtimeLightmap) + { + Hash128 inputSystemHash; + if ((renderer != null && LightmapEditorSettings.GetInputSystemHash(renderer.GetInstanceID(), out inputSystemHash)) + || (terrain != null && LightmapEditorSettings.GetInputSystemHash(terrain.GetInstanceID(), out inputSystemHash))) + { + m_ActiveGameObjectTextureHash = inputSystemHash; + } + else + m_ActiveGameObjectTextureHash = new Hash128(); + } + else + { + m_ActiveGameObjectLightmapIndex = renderer != null ? renderer.lightmapIndex : terrain.lightmapIndex; + m_ActiveGameObjectInstanceId = renderer != null ? renderer.GetInstanceID() : terrain.GetInstanceID(); + } + } + private void UpdateCachedTexture(GITextureType textureType) { if (isIndexBased) diff --git a/Editor/Mono/SceneModeWindows/NavigationWindow.cs b/Editor/Mono/SceneModeWindows/NavigationWindow.cs index 0478f66928..183bd82917 100644 --- a/Editor/Mono/SceneModeWindows/NavigationWindow.cs +++ b/Editor/Mono/SceneModeWindows/NavigationWindow.cs @@ -588,7 +588,7 @@ static void DisplayAgentControls(Object target, SceneView sceneView) } var showAgentNeighbours = NavMeshVisualizationSettings.showAgentNeighbours; - if (showAgentNeighbours != EditorGUILayout.Toggle(EditorGUIUtility.TrTextContent("Show Neighbours", "Show the agent neighbours cosidered during simulation."), showAgentNeighbours)) + if (showAgentNeighbours != EditorGUILayout.Toggle(EditorGUIUtility.TrTextContent("Show Neighbours", "Show the agent neighbours considered during simulation."), showAgentNeighbours)) { NavMeshVisualizationSettings.showAgentNeighbours = !showAgentNeighbours; bRepaint = true; diff --git a/Editor/Mono/SceneModeWindows/OcclusionCullingWindow.cs b/Editor/Mono/SceneModeWindows/OcclusionCullingWindow.cs index 1726a789cf..51ed489cc1 100644 --- a/Editor/Mono/SceneModeWindows/OcclusionCullingWindow.cs +++ b/Editor/Mono/SceneModeWindows/OcclusionCullingWindow.cs @@ -42,7 +42,7 @@ class Styles public GUIContent seeVisualizationInScene = EditorGUIUtility.TrTextContent("See the occlusion culling visualization in the Scene View based on the selected Camera."); public GUIContent noOcclusionData = EditorGUIUtility.TrTextContent("No occlusion data has been baked."); public GUIContent smallestHole = EditorGUIUtility.TrTextContent("Smallest Hole", "Smallest hole in the geometry through which the camera is supposed to see. The single float value of the parameter represents the diameter of the imaginary smallest hole, i.e. the maximum extent of a 3D object that fits through the hole."); - public GUIContent backfaceThreshold = EditorGUIUtility.TrTextContent("Backface Threshold", "The backface threshold is a size optimization that reduces unnecessary details by testing backfaces. A value of 100 is robust and never removes any backfaces. A value of 5 aggressively reduces the data based on locations with visible backfaces. The idea is that typically valid camera positions cannot see many backfaces. For example geometry under terrain and inside solid objects can be removed."); + public GUIContent backfaceThreshold = EditorGUIUtility.TrTextContent("Backface Threshold", "The backface threshold is a size optimization that reduces unnecessary details by testing backfaces. A value of 100 is robust and never removes any backfaces. A value of 5 aggressively reduces the data based on locations with visible backfaces. The idea is that typically valid camera positions cannot see many backfaces. For example, geometry under terrain and inside solid objects can be removed."); public GUIContent farClipPlane = EditorGUIUtility.TrTextContent("Far Clip Plane", "Far Clip Plane used during baking. This should match the largest far clip plane used by any camera in the scene. A value of 0.0 sets the far plane to Infinity."); public GUIContent smallestOccluder = EditorGUIUtility.TrTextContent("Smallest Occluder", "The size of the smallest object that will be used to hide other objects when doing occlusion culling. For example, if a value of 4 is chosen, then all the objects that are higher or wider than 4 meters will block visibility and the objects that are smaller than that will not. This value is a tradeoff between occlusion accuracy and storage size."); public GUIContent defaultParameterText = EditorGUIUtility.TrTextContent("Default Parameters", "The default parameters guarantee that any given scene computes fast and the occlusion culling results are good. As the parameters are always scene specific, better results will be achieved when fine tuning the parameters on a scene to scene basis. All the parameters are dependent on the unit scale of the scene and it is imperative that the unit scale parameter is set correctly before setting the default values."); diff --git a/Editor/Mono/SceneModeWindows/PhysicsDebugWindow.cs b/Editor/Mono/SceneModeWindows/PhysicsDebugWindow.cs index 0a82854cfd..59ae581bd0 100644 --- a/Editor/Mono/SceneModeWindows/PhysicsDebugWindow.cs +++ b/Editor/Mono/SceneModeWindows/PhysicsDebugWindow.cs @@ -50,7 +50,7 @@ private static class Style public static readonly GUIContent showLayers = EditorGUIUtility.TrTextContent("Show Layers", "Show selected layers"); public static readonly GUIContent showPhysicsScenes = EditorGUIUtility.TrTextContent("Show Physics Scene", "Show selected physics scenes"); public static readonly GUIContent showStaticCollider = EditorGUIUtility.TrTextContent("Show Static Colliders", "Show collision geometry from Colliders that do not have a Rigidbody"); - public static readonly GUIContent showTriggers = EditorGUIUtility.TrTextContent("Show Triggers", "Show collision geometry from Colliders that have 'isTrigge' enabled"); + public static readonly GUIContent showTriggers = EditorGUIUtility.TrTextContent("Show Triggers", "Show collision geometry from Colliders that have 'isTrigger' enabled"); public static readonly GUIContent showRigibodies = EditorGUIUtility.TrTextContent("Show Rigidbodies", "Show collision geometry from Rigidbodies"); public static readonly GUIContent showKinematicBodies = EditorGUIUtility.TrTextContent("Show Kinematic Bodies", "Show collision geometry from Kinematic Rigidbodies"); public static readonly GUIContent showSleepingBodies = EditorGUIUtility.TrTextContent("Show Sleeping Bodies", "Show collision geometry from Sleeping Rigidbodies"); diff --git a/Editor/Mono/SceneView/SceneView.cs b/Editor/Mono/SceneView/SceneView.cs index 5dec8f750e..4f3edbc399 100644 --- a/Editor/Mono/SceneView/SceneView.cs +++ b/Editor/Mono/SceneView/SceneView.cs @@ -465,6 +465,7 @@ public SceneViewState sceneViewState [Serializable] public class CameraSettings { + const float defaultEasingDuration = .4f; const float kAbsoluteSpeedMin = .01f; const float kAbsoluteSpeedMax = 99f; const float kAbsoluteEasingDurationMin = .1f; @@ -482,6 +483,8 @@ public class CameraSettings bool m_EasingEnabled; [SerializeField] float m_EasingDuration; + [SerializeField] + bool m_AccelerationEnabled; [SerializeField] float m_FieldOfView; @@ -501,12 +504,13 @@ public CameraSettings() m_SpeedMin = .01f; m_SpeedMax = 2f; m_EasingEnabled = true; - m_EasingDuration = .4f; + m_EasingDuration = defaultEasingDuration; fieldOfView = kPerspectiveFov; m_DynamicClip = true; m_OcclusionCulling = false; m_NearClip = .03f; m_FarClip = 10000f; + m_AccelerationEnabled = true; } public float speed @@ -563,6 +567,8 @@ public float speedMax } } + // Easing is applied when starting and stopping movement. When enabled, the camera will lerp from it's + // current speed to the target speed over the course of `CameraSettings.easingDuration` seconds. public bool easingEnabled { get { return m_EasingEnabled; } @@ -584,6 +590,14 @@ public float easingDuration } } + // When acceleration is enabled, camera speed is continuously increased while in motion. When acceleration + // is disabled, speed is a constant value defined by `CameraSettings.speed` + public bool accelerationEnabled + { + get { return m_AccelerationEnabled; } + set { m_AccelerationEnabled = value; } + } + internal void SetSpeedMinMax(float[] floatValues) { // Round to nearest decimal: 2 decimal points when between [0.01, 0.1]; 1 decimal point when between [0.1, 10]; integral between [10, 99] @@ -749,7 +763,7 @@ internal static class Styles public static GUIContent isolationModeOverlayContent = EditorGUIUtility.TrTextContent("Isolation View", ""); public static GUIContent isolationModeExitButton = EditorGUIUtility.TrTextContent("Exit", "Exit isolation mode"); public static GUIContent renderDocContent; - public static GUIContent sceneVisToolbarButtonContent = EditorGUIUtility.TrIconContent("SceneViewVisibility", "Number of hidden objects, click to toggle scene visibility"); + public static GUIContent sceneVisToolbarButtonContent = EditorGUIUtility.TrIconContent("scenevis_hidden", "Number of hidden objects, click to toggle scene visibility"); public static GUIStyle gizmoButtonStyle; public static GUIStyle fxDropDownStyle; public static GUIContent sceneViewCameraContent = EditorGUIUtility.TrIconContent("SceneViewCamera", "Settings for the Scene view camera."); @@ -2250,6 +2264,7 @@ protected virtual void OnGUI() if (evt.type == EventType.Repaint) { s_MouseRects.Clear(); + Tools.InvalidateHandlePosition(); // Some cases that should invalidate the cached position are not handled correctly yet so we refresh it once per frame Profiler.BeginSample("SceneView.Repaint"); } @@ -2282,7 +2297,7 @@ protected virtual void OnGUI() // Use custom scene RenderSettings (if currently showing a custom scene) bool restoreOverrideRenderSettings = false; if (m_CustomScene.IsValid()) - restoreOverrideRenderSettings = Unsupported.SetOverrideRenderSettings(m_CustomScene); + restoreOverrideRenderSettings = Unsupported.SetOverrideLightingSettings(m_CustomScene); SetupCustomSceneLighting(); @@ -2318,7 +2333,7 @@ protected virtual void OnGUI() CleanupCustomSceneLighting(); if (restoreOverrideRenderSettings) - Unsupported.RestoreOverrideRenderSettings(); + Unsupported.RestoreOverrideLightingSettings(); //Ensure that the target texture is clamped [0-1] //This is needed because otherwise gizmo rendering gets all @@ -2382,10 +2397,6 @@ protected virtual void OnGUI() // Calling OnSceneGUI before DefaultHandles, so users can use events before the Default Handles HandleSelectionAndOnSceneGUI(); - // Handle commands - if (evt.type == EventType.ExecuteCommand || evt.type == EventType.ValidateCommand) - CommandsGUI(); - Handles.SetCameraFilterMode(Camera.current, UseSceneFiltering() ? Handles.CameraFilterMode.ShowFiltered : Handles.CameraFilterMode.Off); // Handle scene view motion when this scene view is active @@ -2400,6 +2411,10 @@ protected virtual void OnGUI() // Draw default scene manipulation tools (Move/Rotate/...) DefaultHandles(); + // Handle scene commands after EditorTool.OnSceneGUI so that tools can handle commands + if (evt.type == EventType.ExecuteCommand || evt.type == EventType.ValidateCommand) + CommandsGUI(); + Handles.SetCameraFilterMode(Camera.current, Handles.CameraFilterMode.Off); Handles.SetCameraFilterMode(m_Camera, Handles.CameraFilterMode.Off); @@ -3169,7 +3184,7 @@ public virtual bool FrameSelected(bool lockView, bool instant) viewIsLockedToObject = lockView; FixNegativeSize(); - Bounds bounds = InternalEditorUtility.CalculateSelectionBounds(false, Tools.pivotMode == PivotMode.Pivot); + Bounds bounds = InternalEditorUtility.CalculateSelectionBounds(false, Tools.pivotMode == PivotMode.Pivot, true); // Check active editor for OnGetFrameBounds foreach (Editor editor in activeEditors) diff --git a/Editor/Mono/SceneView/SceneViewMotion.cs b/Editor/Mono/SceneView/SceneViewMotion.cs index e884b6a403..f55ae516a2 100644 --- a/Editor/Mono/SceneView/SceneViewMotion.cs +++ b/Editor/Mono/SceneView/SceneViewMotion.cs @@ -16,7 +16,7 @@ internal static class SceneViewMotion static bool s_Initialized; static SceneView s_SceneView; static Vector3 s_Motion; - static float k_FlySpeed = 9f; + internal static float k_FlySpeed = 9f; static float s_FlySpeedTarget = 0f; const float k_FlySpeedAcceleration = 1.8f; static float s_StartZoom = 0f, s_ZoomSpeed = 0f; @@ -25,6 +25,11 @@ internal static class SceneViewMotion static bool s_Moving; static AnimVector3 s_FlySpeed = new AnimVector3(Vector3.zero); + internal static Vector3 cameraSpeed + { + get { return s_FlySpeed.value; } + } + enum MotionState { kInactive, @@ -113,9 +118,16 @@ static Vector3 GetMovementDirection() speedModifier *= 5f; if (s_Moving) - s_FlySpeedTarget = s_FlySpeedTarget < Mathf.Epsilon ? k_FlySpeed : s_FlySpeedTarget * Mathf.Pow(k_FlySpeedAcceleration, deltaTime); + { + if (s_SceneView.cameraSettings.accelerationEnabled) + s_FlySpeedTarget = s_FlySpeedTarget < Mathf.Epsilon ? k_FlySpeed : s_FlySpeedTarget * Mathf.Pow(k_FlySpeedAcceleration, deltaTime); + else + s_FlySpeedTarget = k_FlySpeed; + } else + { s_FlySpeedTarget = 0f; + } if (s_SceneView.cameraSettings.easingEnabled) { @@ -377,16 +389,18 @@ private static void HandleKeyDown(SceneView sceneView) private static void HandleScrollWheel(SceneView view, bool zoomTowardsCenter) { - if (Tools.s_LockedViewTool == ViewTool.FPS && s_Moving) + if (Tools.s_LockedViewTool == ViewTool.FPS) { float scrollWheelDelta = Event.current.delta.y * s_FPSScrollWheelMultiplier; view.cameraSettings.speedNormalized -= scrollWheelDelta; - float cameraSpeed = view.cameraSettings.speed; - string cameraSpeedDisplayValue = cameraSpeed.ToString(cameraSpeed < 0.1f ? "F2" : cameraSpeed < 10f ? "F1" : "F0"); - if (cameraSpeed < 0.1f) + float cameraSettingsSpeed = view.cameraSettings.speed; + string cameraSpeedDisplayValue = cameraSettingsSpeed.ToString(cameraSettingsSpeed < 0.1f ? "F2" : cameraSettingsSpeed < 10f ? "F1" : "F0"); + if (cameraSettingsSpeed < 0.1f) cameraSpeedDisplayValue = cameraSpeedDisplayValue.TrimStart(new Char[] {'0'}); - GUIContent cameraSpeedContent = EditorGUIUtility.TempContent(string.Format("{0}x", cameraSpeedDisplayValue)); + GUIContent cameraSpeedContent = EditorGUIUtility.TempContent(string.Format("{0}{1}", + cameraSpeedDisplayValue, + s_SceneView.cameraSettings.accelerationEnabled ? "x" : "")); view.ShowNotification(cameraSpeedContent, .5f); } diff --git a/Editor/Mono/SceneView/SceneViewOverlay.cs b/Editor/Mono/SceneView/SceneViewOverlay.cs index 82b5ad7efc..825c7bdb17 100644 --- a/Editor/Mono/SceneView/SceneViewOverlay.cs +++ b/Editor/Mono/SceneView/SceneViewOverlay.cs @@ -111,7 +111,7 @@ private void WindowTrampoline(int id) EditorGUIUtility.ResetGUIState(); GUI.skin = EditorGUIUtility.GetBuiltinSkin(EditorSkin.Scene); EditorStyles.UpdateSkinCache(1); // EditorResources.h defines this as the index for the dark skin - GUILayout.BeginHorizontal(); + GUILayout.BeginHorizontal(GUILayout.Width(210)); GUILayout.FlexibleSpace(); GUILayout.BeginVertical(win.m_Title, GUI.skin.window); win.m_SceneViewFunc(win.m_Target, m_SceneView); diff --git a/Editor/Mono/SceneView/SceneViewStageHandling.cs b/Editor/Mono/SceneView/SceneViewStageHandling.cs index e73661f5a2..5299d99614 100644 --- a/Editor/Mono/SceneView/SceneViewStageHandling.cs +++ b/Editor/Mono/SceneView/SceneViewStageHandling.cs @@ -160,6 +160,10 @@ void HandleFirstTimePrefabStageIsOpened(StageNavigationItem stage) if (!HasAnyActiveLights(stage.prefabStage.scene)) m_SceneView.sceneLighting = false; + // Default to not showing skybox if user did not specify a custom environment scene. + if (string.IsNullOrEmpty(stage.prefabStage.scene.path)) + m_SceneView.sceneViewState.showSkybox = false; + // For UI to frame properly we need to delay one full Update for the layouting to have been processed EditorApplication.update += DelayedFraming; } diff --git a/Editor/Mono/SceneVisibilityHierarchyGUI.cs b/Editor/Mono/SceneVisibilityHierarchyGUI.cs index 3e49084ea9..494b691611 100644 --- a/Editor/Mono/SceneVisibilityHierarchyGUI.cs +++ b/Editor/Mono/SceneVisibilityHierarchyGUI.cs @@ -70,7 +70,7 @@ public static Color GetItemBackgroundColor(bool isHovered, bool isSelected, bool } } - private const int k_VisibilityIconPadding = 4; + private const int k_VisibilityIconPadding = 0; private const int k_IconWidth = 16; private static readonly float k_sceneHeaderOverflow = GameObjectTreeViewGUI.GameObjectStyles.sceneHeaderBg.fixedHeight - EditorGUIUtility.singleLineHeight; private static bool m_PrevItemWasScene; @@ -108,7 +108,7 @@ public static void DoItemGUI(Rect rect, GameObjectTreeViewItem goItem, bool isSe if (m_PrevItemWasScene && !isSelected && !isHovered) rect.yMin += k_sceneHeaderOverflow; - DrawItemBackground(rect, isSelected, isHovered, isFocused); + DrawItemBackground(rect, false, isSelected, isHovered, isFocused); DrawGameObjectItem(iconRect, gameObject, isHovered, isIconHovered); m_PrevItemWasScene = false; } @@ -117,21 +117,41 @@ public static void DoItemGUI(Rect rect, GameObjectTreeViewItem goItem, bool isSe Scene scene = goItem.scene; if (scene.IsValid()) { + DrawItemBackground(rect, true, isSelected, isHovered, isFocused); DrawSceneItem(iconRect, scene, isHovered, isIconHovered); m_PrevItemWasScene = true; } } } - private static void DrawItemBackground(Rect rect, bool isSelected, bool isHovered, bool isFocused) + private static void DrawItemBackground(Rect rect, bool isScene, bool isSelected, bool isHovered, bool isFocused) { if (Event.current.type == EventType.Repaint) { rect.width = utilityBarWidth; - using (new GUI.BackgroundColorScope(Styles.GetItemBackgroundColor(isHovered, isSelected, isFocused))) + if (isScene) { - GUI.Label(rect, GUIContent.none, GameObjectTreeViewGUI.GameObjectStyles.hoveredItemBackgroundStyle); + if (isSelected) + { + TreeViewGUI.Styles.selectionStyle.Draw(rect, false, false, true, isFocused); + } + else if (isHovered) + { + using (new GUI.BackgroundColorScope(GameObjectTreeViewGUI.GameObjectStyles.hoveredBackgroundColor)) + { + GUI.Label(rect, GUIContent.none, GameObjectTreeViewGUI.GameObjectStyles.hoveredItemBackgroundStyle); + } + } + } + else + { + using (new GUI.BackgroundColorScope(Styles.GetItemBackgroundColor(isHovered, isSelected, isFocused)) + ) + { + GUI.Label(rect, GUIContent.none, + GameObjectTreeViewGUI.GameObjectStyles.hoveredItemBackgroundStyle); + } } } } @@ -166,41 +186,29 @@ private static void DrawGameObjectItem(Rect rect, GameObject gameObject, bool is private static void DrawSceneItem(Rect rect, Scene scene, bool isItemHovered, bool isIconHovered) { - var isHidden = SceneVisibilityManager.instance.AreAllDescendantsHidden(scene); + var state = SceneVisibilityManager.instance.GetSceneState(scene); bool shouldDisplayIcon = true; + Styles.IconState iconState = isIconHovered ? Styles.iconHovered : Styles.iconNormal; GUIContent icon; - if (!isIconHovered) + if (state == SceneVisibilityManager.SceneState.AllHidden) { - if (isHidden) - { - icon = Styles.iconNormal.hiddenAll; - } - else if (SceneVisibilityManager.instance.AreAnyDescendantsHidden(scene)) - { - icon = Styles.iconNormal.hiddenMixed; - } - else - { - icon = Styles.iconNormal.visibleAll; - shouldDisplayIcon = isItemHovered; - } + icon = iconState.hiddenAll; + } + else if (state == SceneVisibilityManager.SceneState.Mixed) + { + icon = iconState.visibleMixed; } else { - icon = Styles.iconSceneHovered; + icon = iconState.visibleAll; + shouldDisplayIcon = isItemHovered; } + if (shouldDisplayIcon && GUI.Button(rect, icon, Styles.sceneVisibilityStyle)) { - if (isHidden) - { - SceneVisibilityManager.instance.Show(scene); - } - else - { - SceneVisibilityManager.instance.Hide(scene); - } + SceneVisibilityManager.instance.ToggleScene(scene, state); } } } diff --git a/Editor/Mono/SceneVisibilityManager.cs b/Editor/Mono/SceneVisibilityManager.cs index b912443ff0..9fb144e682 100644 --- a/Editor/Mono/SceneVisibilityManager.cs +++ b/Editor/Mono/SceneVisibilityManager.cs @@ -15,7 +15,28 @@ namespace UnityEditor { public class SceneVisibilityManager : ScriptableSingleton { + internal class ShortcutContext : IShortcutToolContext + { + public bool active + { + get + { + var focusedWindow = EditorWindow.focusedWindow; + if (focusedWindow != null) + { + return (focusedWindow.GetType() == typeof(SceneView) || + focusedWindow.GetType() == typeof(SceneHierarchyWindow)); + } + + return false; + } + } + } + + private static ShortcutContext s_ShortcutContext; + public static event Action visibilityChanged; + internal static event Action currentStageIsolated; private readonly static List m_RootBuffer = new List(); @@ -41,6 +62,8 @@ private static void Initialize() SceneVisibilityState.internalStructureChanged += InternalStructureChanged; PrefabStage stage = StageNavigationManager.instance.GetCurrentPrefabStage(); SceneVisibilityState.SetPrefabStageScene(stage == null ? default(Scene) : stage.scene); + s_ShortcutContext = new ShortcutContext(); + EditorApplication.delayCall += () => ShortcutIntegration.instance.contextManager.RegisterToolContext(s_ShortcutContext); } private static void InternalStructureChanged() @@ -169,6 +192,12 @@ public void Hide(GameObject gameObject, bool includeDescendants) VisibilityChanged(); } + [Shortcut("Scene Visibility/Show All")] + internal static void ShowAllShortcut() + { + instance.ShowAll(); + } + public void ShowAll() { Undo.RecordObject(SceneVisibilityState.GetInstance(), "Show All"); @@ -239,6 +268,13 @@ public bool IsHidden(GameObject gameObject, bool includeDescendants = false) return SceneVisibilityState.IsGameObjectHidden(gameObject); } + static bool IsIgnoredBySceneVisibility(GameObject go) + { + var hideFlags = HideFlags.HideInHierarchy | HideFlags.DontSaveInBuild | HideFlags.DontSaveInEditor; + + return (go.hideFlags & hideFlags) != 0; + } + public bool AreAllDescendantsHidden(Scene scene) { if (scene.rootCount == 0) @@ -247,6 +283,9 @@ public bool AreAllDescendantsHidden(Scene scene) scene.GetRootGameObjects(m_RootBuffer); foreach (GameObject root in m_RootBuffer) { + if (IsIgnoredBySceneVisibility(root)) + continue; + if (!SceneVisibilityState.IsHierarchyHidden(root)) return false; } @@ -259,6 +298,22 @@ public bool AreAnyDescendantsHidden(Scene scene) return SceneVisibilityState.HasHiddenGameObjects(scene); } + internal enum SceneState + { + AllHidden, + AllVisible, + Mixed + } + + internal SceneState GetSceneState(Scene scene) + { + if (AreAllDescendantsHidden(scene)) + return SceneState.AllHidden; + if (AreAnyDescendantsHidden(scene)) + return SceneState.Mixed; + return SceneState.AllVisible; + } + public void Show(GameObject[] gameObjects, bool includeDescendants) { Undo.RecordObject(SceneVisibilityState.GetInstance(), "Show GameObjects"); @@ -316,8 +371,8 @@ public bool AreAllDescendantsVisible(GameObject gameObject) } //SHORTCUTS - [Shortcut("Scene Visibility/Toggle Selection Visibility")] - static void ToggleSelectionVisibility() + [Shortcut("Scene Visibility/Toggle Visibility for Selection")] + private static void ToggleSelectionVisibility() { if (Selection.gameObjects.Length > 0) { @@ -331,14 +386,14 @@ static void ToggleSelectionVisibility() shouldHide = false; } - Undo.RecordObject(SceneVisibilityState.GetInstance(), "Toggle Selection Visibility"); + Undo.RecordObject(SceneVisibilityState.GetInstance(), "Toggle Visibility for Selection"); SceneVisibilityState.SetGameObjectsHidden(Selection.gameObjects, shouldHide, false); instance.VisibilityChanged(); } } - [Shortcut("Scene Visibility/Toggle Selection And Descendants Visibility")] - static void ToggleSelectionAndDescendantsVisibility() + [Shortcut("Scene Visibility/Toggle Visibility for Selection and Children", typeof(ShortcutContext), KeyCode.H)] + private static void ToggleSelectionAndDescendantsVisibility() { if (Selection.gameObjects.Length > 0) { @@ -352,7 +407,7 @@ static void ToggleSelectionAndDescendantsVisibility() shouldHide = false; } - Undo.RecordObject(SceneVisibilityState.GetInstance(), "Toggle Visibility And Children"); + Undo.RecordObject(SceneVisibilityState.GetInstance(), "Toggle Visibility for Selection and Children"); SceneVisibilityState.SetGameObjectsHidden(Selection.gameObjects, shouldHide, true); instance.VisibilityChanged(); } @@ -419,12 +474,12 @@ private static void RevertIsolationCurrentStage() } [Shortcut("Scene Visibility/Exit Isolation")] - static void ExitIsolationShortcut() + private static void ExitIsolationShortcut() { instance.ExitIsolation(); } - [Shortcut("Scene Visibility/Toggle Selection And Descendants")] + [Shortcut("Scene Visibility/Toggle Isolation for Selection and Children", typeof(ShortcutContext), KeyCode.H, ShortcutModifiers.Shift)] static void ToggleIsolateSelectionAndDescendantsShortcut() { instance.ToggleIsolateSelectionAndDescendants(); @@ -432,7 +487,7 @@ static void ToggleIsolateSelectionAndDescendantsShortcut() internal void ToggleIsolateSelectionAndDescendants() { - Undo.RecordObject(SceneVisibilityState.GetInstance(), "Toggle Isolation on Selection And Children"); + Undo.RecordObject(SceneVisibilityState.GetInstance(), "Toggle Isolation for Selection and Children"); if (!IsCurrentStageIsolated()) { @@ -453,7 +508,7 @@ internal void ToggleIsolateSelectionAndDescendants() } } - [Shortcut("Scene Visibility/Toggle Isolation on Selection")] + [Shortcut("Scene Visibility/Toggle Isolation for Selection")] static void ToggleIsolateSelectionShortcut() { instance.ToggleIsolateSelection(); @@ -461,7 +516,7 @@ static void ToggleIsolateSelectionShortcut() internal void ToggleIsolateSelection() { - Undo.RecordObject(SceneVisibilityState.GetInstance(), "Toggle Isolation on Selection"); + Undo.RecordObject(SceneVisibilityState.GetInstance(), "Toggle Isolation for Selection"); if (!IsCurrentStageIsolated()) { @@ -481,5 +536,17 @@ internal void ToggleIsolateSelection() VisibilityChanged(); } } + + internal void ToggleScene(Scene scene, SceneState state) + { + if (state == SceneState.AllVisible || state == SceneState.Mixed) + { + Hide(scene); + } + else + { + Show(scene); + } + } } } diff --git a/Editor/Mono/ScriptAttributeGUI/Implementations/ExposedReferenceDrawer.cs b/Editor/Mono/ScriptAttributeGUI/Implementations/ExposedReferenceDrawer.cs index f0f15fdd38..c84785b4f2 100644 --- a/Editor/Mono/ScriptAttributeGUI/Implementations/ExposedReferenceDrawer.cs +++ b/Editor/Mono/ScriptAttributeGUI/Implementations/ExposedReferenceDrawer.cs @@ -16,7 +16,7 @@ abstract class BaseExposedPropertyDrawer : UnityEditor.PropertyDrawer protected readonly GUIContent ExposePropertyContent = EditorGUIUtility.TrTextContent("Expose Property"); protected readonly GUIContent UnexposePropertyContent = EditorGUIUtility.TrTextContent("Unexpose Property"); protected readonly GUIContent NotFoundOn = EditorGUIUtility.TrTextContent("not found on"); - protected readonly GUIContent OverridenByContent = EditorGUIUtility.TrTextContent("Overriden by "); + protected readonly GUIContent OverridenByContent = EditorGUIUtility.TrTextContent("Overridden by "); private GUIContent m_ModifiedLabel = new GUIContent(); diff --git a/Editor/Mono/ScriptAttributeGUI/Implementations/PropertyDrawers.cs b/Editor/Mono/ScriptAttributeGUI/Implementations/PropertyDrawers.cs index 7da11f8c38..c2a8878d28 100644 --- a/Editor/Mono/ScriptAttributeGUI/Implementations/PropertyDrawers.cs +++ b/Editor/Mono/ScriptAttributeGUI/Implementations/PropertyDrawers.cs @@ -23,6 +23,57 @@ public override void OnGUI(Rect position, SerializedProperty property, GUIConten } } + [CustomPropertyDrawer(typeof(MinAttribute))] + internal sealed class MinDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + EditorGUI.BeginChangeCheck(); + EditorGUI.DefaultPropertyField(position, property, label); + if (EditorGUI.EndChangeCheck()) + { + MinAttribute minAttribute = (MinAttribute)attribute; + if (property.propertyType == SerializedPropertyType.Float) + { + property.floatValue = Mathf.Max(minAttribute.min, property.floatValue); + } + else if (property.propertyType == SerializedPropertyType.Integer) + { + property.intValue = Mathf.Max((int)minAttribute.min, property.intValue); + } + else if (property.propertyType == SerializedPropertyType.Vector2) + { + var value = property.vector2Value; + property.vector2Value = new Vector2(Mathf.Max(minAttribute.min, value.x), Mathf.Max(minAttribute.min, value.y)); + } + else if (property.propertyType == SerializedPropertyType.Vector2Int) + { + var value = property.vector2IntValue; + property.vector2IntValue = new Vector2Int(Mathf.Max((int)minAttribute.min, value.x), Mathf.Max((int)minAttribute.min, value.y)); + } + else if (property.propertyType == SerializedPropertyType.Vector3) + { + var value = property.vector3Value; + property.vector3Value = new Vector3(Mathf.Max(minAttribute.min, value.x), Mathf.Max(minAttribute.min, value.y), Mathf.Max(minAttribute.min, value.z)); + } + else if (property.propertyType == SerializedPropertyType.Vector3Int) + { + var value = property.vector3IntValue; + property.vector3IntValue = new Vector3Int(Mathf.Max((int)minAttribute.min, value.x), Mathf.Max((int)minAttribute.min, value.y), Mathf.Max((int)minAttribute.min, value.z)); + } + else if (property.propertyType == SerializedPropertyType.Vector4) + { + var value = property.vector4Value; + property.vector4Value = new Vector4(Mathf.Max(minAttribute.min, value.x), Mathf.Max(minAttribute.min, value.y), Mathf.Max(minAttribute.min, value.z), Mathf.Max(minAttribute.min, value.w)); + } + else + { + EditorGUI.LabelField(position, label.text, "Use Min with float, int or Vector."); + } + } + } + } + [CustomPropertyDrawer(typeof(MultilineAttribute))] internal sealed class MultilineDrawer : PropertyDrawer { diff --git a/Editor/Mono/ScriptAttributeGUI/ScriptAttributeUtility.cs b/Editor/Mono/ScriptAttributeGUI/ScriptAttributeUtility.cs index 214c01fa34..de119c4a46 100644 --- a/Editor/Mono/ScriptAttributeGUI/ScriptAttributeUtility.cs +++ b/Editor/Mono/ScriptAttributeGUI/ScriptAttributeUtility.cs @@ -213,17 +213,18 @@ private static FieldInfo GetFieldInfoFromPropertyPath(Type host, string path, ou { FieldInfo field = null; - var regex = new Regex(@"\.Array\.data\[[0-9]+\]"); - var match = regex.IsMatch(path); - if (match) - path = regex.Replace(path, ""); + const string arrayData = @"\.Array\.data\[[0-9]+\]"; + // we are looking for array element only when the path ends with Array.data[x] + var lookingForArrayElement = Regex.IsMatch(path, arrayData + "$"); + // remove any Array.data[x] from the path because it is prevents cache searching. + path = Regex.Replace(path, arrayData, ".___ArrayElement___"); Cache cache = new Cache(host, path); if (s_FieldInfoFromPropertyPathCache.TryGetValue(cache, out field)) { type = field?.FieldType; // we want to get the element type if we are looking for Array.data[x] - if (match && type != null && type.IsArrayOrList()) + if (lookingForArrayElement && type != null && type.IsArrayOrList()) type = type.GetArrayOrListElementType(); return field; } @@ -251,8 +252,9 @@ private static FieldInfo GetFieldInfoFromPropertyPath(Type host, string path, ou field = foundField; type = field.FieldType; // we want to get the element type if we are looking for Array.data[x] - if (match && type.IsArrayOrList()) + if (i < parts.Length - 1 && parts[i + 1] == "___ArrayElement___" && type.IsArrayOrList()) { + i++; // skip the "___ArrayElement___" part type = type.GetArrayOrListElementType(); } } diff --git a/Editor/Mono/ScriptEditorUtility.cs b/Editor/Mono/ScriptEditorUtility.cs index 1ae3f40b96..5503cb99a7 100644 --- a/Editor/Mono/ScriptEditorUtility.cs +++ b/Editor/Mono/ScriptEditorUtility.cs @@ -8,7 +8,9 @@ using System; using System.IO; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; +using Unity.CodeEditor; using UnityEditor.Utils; namespace UnityEditorInternal @@ -16,7 +18,7 @@ namespace UnityEditorInternal public class ScriptEditorUtility { // Keep in sync with enum ScriptEditorType in ExternalEditor.h - public enum ScriptEditor { SystemDefault = 0, MonoDevelop = 1, VisualStudio = 2, VisualStudioExpress = 3, VisualStudioCode = 4, Rider = 5, Other = 32 } + public enum ScriptEditor { SystemDefault = 0, MonoDevelop = 1, VisualStudio = 2, VisualStudioExpress = 3, Other = 32 } public struct Installation { @@ -26,16 +28,18 @@ public struct Installation static readonly List> k_PathCallbacks = new List>(); + [Obsolete("Use UnityEditor.ScriptEditor.Register()", false)] public static void RegisterIde(Func pathCallBack) { k_PathCallbacks.Add(pathCallBack); } + [Obsolete("This functionality is going to be removed. See IExternalCodeEditor for more information", false)] public static ScriptEditor GetScriptEditorFromPath(string path) { string lowerCasePath = path.ToLower(); - if (lowerCasePath == "internal") + if (lowerCasePath == CodeEditor.SystemDefaultPath) return ScriptEditor.SystemDefault; if (lowerCasePath.Contains("monodevelop") || lowerCasePath.Contains("xamarinstudio") || lowerCasePath.Contains("xamarin studio")) @@ -47,14 +51,6 @@ public static ScriptEditor GetScriptEditorFromPath(string path) if (lowerCasePath.EndsWith("vcsexpress.exe")) return ScriptEditor.VisualStudioExpress; - string filename = Path.GetFileName(Paths.UnifyDirectorySeparator(lowerCasePath)).Replace(" ", ""); - - if (filename == "code.exe" || filename == "visualstudiocode.app" || filename == "vscode.app" || filename == "code.app" || filename == "code") - return ScriptEditor.VisualStudioCode; - - if (filename.StartsWith("rider")) - return ScriptEditor.Rider; - // Visual Studio for Mac is based on MonoDevelop if (IsVisualStudioForMac(path)) return ScriptEditor.MonoDevelop; @@ -71,25 +67,17 @@ internal static bool IsVisualStudioForMac(string path) public static string GetExternalScriptEditor() { - var editor = EditorPrefs.GetString("kScriptsDefaultApp"); - - if (!string.IsNullOrEmpty(editor)) - return editor; - - // If no script editor is set, try to use first found supported one. - var editorPaths = GetFoundScriptEditorPaths(Application.platform); - - if (editorPaths.Count > 0) - return editorPaths.Keys.ToArray()[0]; - - return string.Empty; + return CodeEditor.CurrentEditorInstallation; } + [Obsolete("This method has been moved to CodeEditor.SetExternalScriptEditor", false)] public static void SetExternalScriptEditor(string path) { - EditorPrefs.SetString("kScriptsDefaultApp", path); + CodeEditor.SetExternalScriptEditor(path); } + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete("This functionality has been moved to the IExternalCodeEditor packages", true)] static string GetScriptEditorArgsKey(string path) { // Starting in Unity 5.5, we support setting script editor arguments on OSX and @@ -122,27 +110,23 @@ static string GetDefaultStringEditorArgs() public static string GetExternalScriptEditorArgs() { - string editor = GetExternalScriptEditor(); - var scriptEditor = GetScriptEditorFromPath(editor); - - if (scriptEditor != ScriptEditor.Other) - return ""; - - return EditorPrefs.GetString(GetScriptEditorArgsKey(editor), GetDefaultStringEditorArgs()); + throw new NotSupportedException("This functionality has been moved to the IExternalCodeEditor packages"); } + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete("This functionality has been moved to the IExternalCodeEditor packages", true)] public static void SetExternalScriptEditorArgs(string args) { - string editor = GetExternalScriptEditor(); - - EditorPrefs.SetString(GetScriptEditorArgsKey(editor), args); + throw new NotSupportedException("This functionality has been moved to the IExternalCodeEditor packages"); } + [Obsolete("Use UnityEditor.ScriptEditor.GetCurrentEditor()", false)] public static ScriptEditor GetScriptEditorFromPreferences() { - return GetScriptEditorFromPath(GetExternalScriptEditor()); + return GetScriptEditorFromPath(CodeEditor.CurrentEditorInstallation); } + [Obsolete("This method is being internalized, please use UnityEditorInternal.CodeEditorUtility.GetFoundScriptEditorPaths", false)] public static Dictionary GetFoundScriptEditorPaths(RuntimePlatform platform) { var result = new Dictionary(); diff --git a/Editor/Mono/Scripting/APIUpdater/APIUpdaterAssemblyHelper.cs b/Editor/Mono/Scripting/APIUpdater/APIUpdaterAssemblyHelper.cs index c655f1cf54..4a72c252f2 100644 --- a/Editor/Mono/Scripting/APIUpdater/APIUpdaterAssemblyHelper.cs +++ b/Editor/Mono/Scripting/APIUpdater/APIUpdaterAssemblyHelper.cs @@ -20,12 +20,15 @@ internal class APIUpdaterAssemblyHelper { // See AssemblyUpdater/Program.cs internal const byte Success = 0x00; + internal const byte FirstSuccessStatus = (1 << 3); + internal const byte FirstErrorStatus = (1 << 7); + + internal const byte ContainsUpdaterConfigurations = (1 << 3) + 2; internal const byte UpdatesApplied = (1 << 3) + 3; internal static int Run(string arguments, string workingDir, out string stdOut, out string stdErr) { - var assemblyUpdaterPath = EditorApplication.applicationContentsPath + "/Tools/ScriptUpdater/AssemblyUpdater.exe"; var monodistribution = MonoInstallationFinder.GetMonoInstallation("MonoBleedingEdge"); var monoexe = Path.Combine(monodistribution, "bin/mono"); @@ -38,7 +41,7 @@ internal static int Run(string arguments, string workingDir, out string stdOut, var startInfo = new ProcessStartInfo { - Arguments = assemblyUpdaterPath + " " + arguments, + Arguments = AssemblyUpdaterPath() + " " + arguments, CreateNoWindow = true, FileName = monoexe, RedirectStandardError = true, @@ -59,6 +62,14 @@ internal static int Run(string arguments, string workingDir, out string stdOut, return assemblyUpdaterProcess.ExitCode; } + static string AssemblyUpdaterPath() + { + var unescapedAssemblyUpdaterPath = EditorApplication.applicationContentsPath + "/Tools/ScriptUpdater/AssemblyUpdater.exe"; + return Application.platform == RuntimePlatform.WindowsEditor + ? CommandLineFormatter.EscapeCharsWindows(unescapedAssemblyUpdaterPath) + : CommandLineFormatter.EscapeCharsQuote(unescapedAssemblyUpdaterPath); + } + internal static string ArgumentsForUpdateAssembly(string assemblyPath, string tempOutputPath, IEnumerable updateConfigSourcePaths) { var assemblyFullPath = ResolveAssemblyPath(assemblyPath); @@ -84,6 +95,14 @@ internal static bool IsError(int exitCode) return (exitCode & (1 << 7)) != 0; } + internal static bool IsUnknown(int exitCode) + { + // See AssemblyUpdater/Program.cs + return exitCode != 0 + && (exitCode & FirstErrorStatus) == 0 // It is not an error code returned from AssemblyUpdater.exe + && (exitCode & FirstSuccessStatus) == 0; // It is not an success code returned from AssemblyUpdater.exe + } + private static string ResolveAssemblyPath(string assemblyPath) { return CommandLineFormatter.PrepareFileName(assemblyPath); diff --git a/Editor/Mono/Scripting/APIUpdater/APIUpdaterManager.bindings.cs b/Editor/Mono/Scripting/APIUpdater/APIUpdaterManager.bindings.cs index 8f6da209dc..12997385c3 100644 --- a/Editor/Mono/Scripting/APIUpdater/APIUpdaterManager.bindings.cs +++ b/Editor/Mono/Scripting/APIUpdater/APIUpdaterManager.bindings.cs @@ -213,16 +213,14 @@ private static void LogTimeoutError(AssemblyUpdaterUpdateTask[] tasks) private static bool HandleAssemblyUpdaterErrors(IEnumerable allTasks) { - var tasksWithErrors = allTasks.Where(t => APIUpdaterAssemblyHelper.IsError(t.Result) || t.Exception != null); + var tasksWithErrors = allTasks.Where(t => APIUpdaterAssemblyHelper.IsError(t.Result) || APIUpdaterAssemblyHelper.IsUnknown(t.Result) || t.Exception != null); if (!tasksWithErrors.Any()) return false; var sb = new StringBuilder(L10n.Tr("Unable to update following assemblies:")); foreach (var updaterTask in tasksWithErrors) { - sb.AppendFormat("{1} (Name = {2}, Error = {3}) (Output: {4}){0}{5}{0}{6}{0}", Environment.NewLine, updaterTask.Candidate.Path, updaterTask.Candidate.Name, updaterTask.Result, updaterTask.OutputPath, updaterTask.StdOut, updaterTask.StdErr); - if (updaterTask.Exception != null) - sb.AppendFormat("\tException: {0}{1}", updaterTask.Exception, Environment.NewLine); + sb.Append(FormatErrorFromTask(updaterTask)); } ReportIgnoredAssembliesDueToPreviousErrors(sb, allTasks.Except(tasksWithErrors)); @@ -231,9 +229,33 @@ private static bool HandleAssemblyUpdaterErrors(IEnumerable completedSuccessfully) { - sb.AppendFormat(L10n.Tr("Following assemblies were successfully updated but due to the failled ones above they were ignored (not copied to the destination folder).")); + sb.AppendFormat(L10n.Tr("Following assemblies were successfully updated but due to the failed ones above they were ignored (not copied to the destination folder).")); foreach (var updaterTask in completedSuccessfully) { sb.AppendFormat("{1} (Result = {2}) (Output: {3}){0}{4}{0}", Environment.NewLine, updaterTask.Candidate.Path, updaterTask.Result, updaterTask.OutputPath, updaterTask.StdOut); diff --git a/Editor/Mono/Scripting/Compilers/CSharpLanguage.cs b/Editor/Mono/Scripting/Compilers/CSharpLanguage.cs index ae8f4c9041..625b4cb7b2 100644 --- a/Editor/Mono/Scripting/Compilers/CSharpLanguage.cs +++ b/Editor/Mono/Scripting/Compilers/CSharpLanguage.cs @@ -132,7 +132,7 @@ public override string GetNamespace(string filePath, string definedSymbols) { var responseFileData = ScriptCompilerBase.ParseResponseFileFromFile( responseFilePath, - Application.dataPath, + Directory.GetParent(Application.dataPath).FullName, GetSystemReferenceDirectories(ApiCompatibilityLevel.NET_4_6)); return GetNamespaceNewRuntime(filePath, definedSymbols, responseFileData.Defines); } @@ -140,7 +140,7 @@ public override string GetNamespace(string filePath, string definedSymbols) { var responseFileData = ScriptCompilerBase.ParseResponseFileFromFile( responseFilePath, - Application.dataPath, + Directory.GetParent(Application.dataPath).FullName, GetSystemReferenceDirectories(ApiCompatibilityLevel.NET_2_0)); return GetNamespaceOldRuntime(filePath, definedSymbols, responseFileData.Defines); } diff --git a/Editor/Mono/Scripting/Compilers/MicrosoftCSharpCompiler.cs b/Editor/Mono/Scripting/Compilers/MicrosoftCSharpCompiler.cs index 6cb59d4192..afc8bfb2e8 100644 --- a/Editor/Mono/Scripting/Compilers/MicrosoftCSharpCompiler.cs +++ b/Editor/Mono/Scripting/Compilers/MicrosoftCSharpCompiler.cs @@ -35,17 +35,6 @@ private void FillCompilerOptions(List arguments, out string argsPrefix) // Case 755238: Always use english for outputing errors, the same way as Mono compilers do arguments.Add("/preferreduilang:en-US"); arguments.Add("/langversion:latest"); - - var platformSupportModule = ModuleManager.FindPlatformSupportModule(ModuleManager.GetTargetStringFromBuildTarget(BuildTarget)); - if (platformSupportModule != null && !m_Island._editor) - { - var compilationExtension = platformSupportModule.CreateCompilationExtension(); - - arguments.AddRange(compilationExtension.GetAdditionalAssemblyReferences().Select(r => "/reference:\"" + r + "\"")); - arguments.AddRange(compilationExtension.GetWindowsMetadataReferences().Select(r => "/reference:\"" + r + "\"")); - arguments.AddRange(compilationExtension.GetAdditionalDefines().Select(d => "/define:" + d)); - arguments.AddRange(compilationExtension.GetAdditionalSourceFiles()); - } } private static void ThrowCompilerNotFoundException(string path) diff --git a/Editor/Mono/Scripting/Compilers/ScriptCompilerBase.cs b/Editor/Mono/Scripting/Compilers/ScriptCompilerBase.cs index c264f87eeb..d06c4d8304 100644 --- a/Editor/Mono/Scripting/Compilers/ScriptCompilerBase.cs +++ b/Editor/Mono/Scripting/Compilers/ScriptCompilerBase.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using UnityEditor.Scripting.ScriptCompilation; +using UnityEditor.Compilation; using UnityEngine; using UnityEditor.Utils; @@ -14,15 +14,6 @@ namespace UnityEditor.Scripting.Compilers { internal abstract class ScriptCompilerBase : IDisposable { - public class ResponseFileData - { - public string[] Defines; - public string[] FullPathReferences; - public bool Unsafe; - public string[] Errors; - public string[] OtherArguments; - } - public class CompilerOption { public string Arg; @@ -115,7 +106,7 @@ protected void AddResponseFileToArguments(List arguments, string respons { var responseFileData = ParseResponseFileFromFile( responseFileName, - Application.dataPath, + Directory.GetParent(Application.dataPath).FullName, GetSystemReferenceDirectories()); foreach (var error in responseFileData.Errors) { @@ -137,6 +128,9 @@ public static ResponseFileData ParseResponseFileFromFile( string projectDirectory, string[] systemReferenceDirectories) { + responseFilePath = Paths.ConvertSeparatorsToUnity(responseFilePath); + projectDirectory = Paths.ConvertSeparatorsToUnity(projectDirectory); + var relativeResponseFilePath = GetRelativePath(responseFilePath, projectDirectory); var responseFile = AssetDatabase.LoadAssetAtPath(relativeResponseFilePath); @@ -175,7 +169,7 @@ static string GetRelativePath(string responseFilePath, string projectDirectory) { if (Path.IsPathRooted(responseFilePath) && responseFilePath.Contains(projectDirectory)) { - responseFilePath = responseFilePath.Substring(Directory.GetParent(Application.dataPath).FullName.Length + 1); + responseFilePath = responseFilePath.Substring(projectDirectory.Length + 1); } return responseFilePath; } @@ -328,18 +322,12 @@ static ResponseFileData ParseResponseFileText( continue; } - var responseReference = reference; - int index = reference.IndexOf('='); - if (index > -1) - { - var assembly = reference.Substring(index + 1); - - responseReference = assembly; - } + var responseReference = index > -1 ? reference.Substring(index + 1) : reference; var fullPathReference = responseReference; - if (!Path.IsPathRooted(responseReference)) + bool isRooted = Path.IsPathRooted(responseReference); + if (!isRooted) { foreach (var directory in systemReferenceDirectories) { @@ -347,6 +335,7 @@ static ResponseFileData ParseResponseFileText( if (File.Exists(systemReferencePath)) { fullPathReference = systemReferencePath; + isRooted = true; break; } } @@ -355,10 +344,11 @@ static ResponseFileData ParseResponseFileText( if (File.Exists(userPath)) { fullPathReference = userPath; + isRooted = true; } } - if (fullPathReference == "") + if (!isRooted) { errors.Add($"{fileName}: not parsed correctly: {responseReference} could not be found as a system library.\n" + "If this was meant as a user reference please provide the relative path from project root (parent of the Assets folder) in the response file."); diff --git a/Editor/Mono/Scripting/ScriptCompilation/AssetPathMetaData.cs b/Editor/Mono/Scripting/ScriptCompilation/AssetPathMetaData.cs index a075bc7b49..bbc1d4d11a 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/AssetPathMetaData.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/AssetPathMetaData.cs @@ -3,6 +3,7 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; +using System.Diagnostics; using System.Runtime.InteropServices; using UnityEngine.Bindings; using UnityEngine.Scripting; @@ -14,6 +15,7 @@ namespace UnityEditor.Scripting.ScriptCompilation [RequiredByNativeCode(GenerateProxy = true)] [NativeHeader("Runtime/Scripting/ScriptingManagedProxySupport.h")] [NativeHeader("Runtime/ScriptingBackend/ScriptingNativeTypes.h")] + [DebuggerDisplay("{DirectoryPath}")] class AssetPathMetaData { public string DirectoryPath; diff --git a/Editor/Mono/Scripting/ScriptCompilation/AutoReferencedPackageAssemblies.cs b/Editor/Mono/Scripting/ScriptCompilation/AutoReferencedPackageAssemblies.cs new file mode 100644 index 0000000000..b918376c56 --- /dev/null +++ b/Editor/Mono/Scripting/ScriptCompilation/AutoReferencedPackageAssemblies.cs @@ -0,0 +1,89 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using System; +using System.Collections.Generic; +using System.Linq; +using static UnityEditor.Scripting.ScriptCompilation.EditorBuildRules; + +namespace UnityEditor.Scripting.ScriptCompilation +{ + static class AutoReferencedPackageAssemblies + { + static HashSet runtimeAssemblyNames = new HashSet(new[] + { + "UnityEngine.UI.dll" + }, + StringComparer.Ordinal); + + static HashSet editorAssemblyNames = new HashSet(new[] + { + "UnityEditor.UI.dll", + "Unity.2D.Tilemap.Editor.dll", + }, + StringComparer.Ordinal); + + // Do not add automatic package references to these assemblies, + // as they also add themselves to all .asmdefs + static HashSet ignoreAssemblies = new HashSet(new[] + { + "UnityEngine.TestRunner.dll", + "UnityEditor.TestRunner.dll" + }, + StringComparer.Ordinal); + + static AutoReferencedPackageAssemblies() + { + editorAssemblyNames.UnionWith(runtimeAssemblyNames); + ignoreAssemblies.UnionWith(editorAssemblyNames); + } + + public static void AddReferences(Dictionary customTargetAssemblies, EditorScriptCompilationOptions options) + { + if (customTargetAssemblies == null || customTargetAssemblies.Count() == 0) + return; + + bool buildingForEditor = (options & EditorScriptCompilationOptions.BuildingForEditor) == EditorScriptCompilationOptions.BuildingForEditor; + + // Add runtime assembly references for the players and + // runtime and editor assembly references for the editor. + var autoReferencedAssemblies = buildingForEditor ? editorAssemblyNames : runtimeAssemblyNames; + + var additionalReferences = new HashSet(); + + foreach (var assemblyName in autoReferencedAssemblies) + { + TargetAssembly targetAssembly; + + // If the automatic referenced package assemblies are in + // the project, then they should be add to all .asmdefs. + if (customTargetAssemblies.TryGetValue(assemblyName, out targetAssembly)) + { + additionalReferences.Add(targetAssembly); + } + } + + // If none of the automatic references package assemblies are in + // the project, do not add anything. + if (!additionalReferences.Any()) + { + return; + } + + foreach (var entry in customTargetAssemblies) + { + var assembly = entry.Value; + + // Do not add additional references to any of the + // automaticly referenced or ignored assemblies + if (ignoreAssemblies.Contains(assembly.Filename)) + continue; + + // Add the automtic references. + var newReferences = assembly.References.Concat(additionalReferences).Distinct().ToList(); + assembly.References = newReferences; + } + } + } +} diff --git a/Editor/Mono/Scripting/ScriptCompilation/CSharpNamespaceParser.cs b/Editor/Mono/Scripting/ScriptCompilation/CSharpNamespaceParser.cs index 39cb9c96be..4a3db6eb65 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/CSharpNamespaceParser.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/CSharpNamespaceParser.cs @@ -32,10 +32,18 @@ internal static class CSharpNamespaceParser static readonly Regex k_Strings = new Regex(@"""((\\[^\n]|[^""\n])*)""", RegexOptions.Compiled); static readonly Regex k_VerbatimStrings = new Regex(@"@(""[^""]*"")+", RegexOptions.Compiled); static readonly Regex k_NewlineRegex = new Regex("\r\n?", RegexOptions.Compiled); - static readonly Regex k_SingleQuote = new Regex(@"((? s_LogWarningAction; + static CSharpNamespaceParser() + { + s_LogWarningAction = Debug.LogWarning; + } + public static string GetNamespace(string sourceCode, string className, params string[] defines) { s_ClassName = className; @@ -48,7 +56,7 @@ public static string GetNamespace(string sourceCode, string className, params st sourceCode = k_VerbatimStrings.Replace(sourceCode, ""); try { - sourceCode = RemoveUnusedDefines(sourceCode, defines.ToList()); + sourceCode = ReduceCodeAndCheckForNamespacesModification(sourceCode); return FindNamespaceForMono(className, sourceCode); } @@ -66,26 +74,30 @@ static string FindNamespaceForMono(string className, string source) var builder = new StringBuilder(source.Length); var buildingNode = false; var buildingClass = false; - var currentNode = parent; + var classAlreadyFoundInOtherNamespace = false; var level = 0; var resNamespace = ""; foreach (var token in split) + { switch (token) { case "{": if (buildingNode) { - currentNode = AddCurrent(level, builder.ToString(), parent); + parent = AddCurrent(level, builder.ToString(), parent); builder = new StringBuilder(); buildingNode = false; } level++; - parent = currentNode; break; case "}": - if (parent.Level > --level) parent = parent.Parent; + if (parent.Level > --level) + { + parent = parent.Parent; + builder.Clear(); + } break; case "class": buildingClass = true; @@ -98,10 +110,21 @@ static string FindNamespaceForMono(string className, string source) if (buildingNode) { var strippedClassname = StripClassName(token); - if (buildingClass && strippedClassname.Equals(className)) + if (buildingClass) { - buildingNode = false; - resNamespace = CollectNamespace(parent); + buildingClass = false; + if (strippedClassname.Equals(className)) + { + var foundNamespace = CollectNamespace(parent); + if (classAlreadyFoundInOtherNamespace && foundNamespace != resNamespace) + { + s_LogWarningAction( + $"Class {className} can not exist in multiple namespaces in the same file, even if one is excluded with preprocessor directives. Please move these to separate files if this is the case."); + } + + resNamespace = foundNamespace; + classAlreadyFoundInOtherNamespace = true; + } } else { @@ -111,6 +134,7 @@ static string FindNamespaceForMono(string className, string source) break; } + } return resNamespace; } @@ -163,21 +187,53 @@ class Node public Node Parent; } - static string RemoveUnusedDefines(string source, List defines) + static bool CheckForNamespaceModification(Stack> namespaceScopeStack, int stackCount) + { + foreach (var tuple in namespaceScopeStack) + { + if (tuple.Item1 && (stackCount == -1 || tuple.Item2 == stackCount)) + return true; + } + return false; + } + + // Reduce code to path that assumes all definitions are true + // Also check for the case where we have a namespace keyword inside any non-outter #if statement. + static string ReduceCodeAndCheckForNamespacesModification(string source) { var stack = new Stack>(); + var namespaceScopeStack = new Stack>(); // var split = source.Split(new[] { "\n" }, StringSplitOptions.RemoveEmptyEntries); var longest = split.Aggregate("", (max, cur) => max.Length > cur.Length ? max : cur); var stringBuilder = new StringBuilder(split.Length * longest.Length); + bool foundNamespace = false; + bool namespaceModificationFound = false; + foreach (var s in split) { + // Check for new namespace declarations, when we have are inside of multiple #ifs, + // and also have seen previous namespace declarations (likely namespace modification). + if (k_Namespace.IsMatch(s)) + { + namespaceModificationFound |= (stack.Count > 1 && CheckForNamespaceModification(namespaceScopeStack, -1)); + foundNamespace = true; + } + if (s.IndexOf("{", StringComparison.Ordinal) >= 0) + { + namespaceScopeStack.Push(new Tuple(foundNamespace, stack.Count)); + foundNamespace = false; + } + if (s.IndexOf("}", StringComparison.Ordinal) >= 0) + { + if (namespaceScopeStack.Count > 0) + namespaceScopeStack.Pop(); + } + + // Handle directives from here on down if (s.IndexOf("#", StringComparison.Ordinal) < 0) { if (stack.Count == 0 || stack.Peek().Item1) - { stringBuilder.Append(s).Append("\n"); - } - continue; } @@ -185,6 +241,7 @@ static string RemoveUnusedDefines(string source, List defines) var directive = match.Groups[1].Value; if (directive == "else") { + namespaceModificationFound |= CheckForNamespaceModification(namespaceScopeStack, stack.Count); var elseEmitting = stack.Peek().Item2; stack.Pop(); stack.Push(new Tuple(elseEmitting, false)); @@ -201,36 +258,26 @@ static string RemoveUnusedDefines(string source, List defines) { throw new UnsupportedDefineExpression(s); } - - if (directive == "define") - { - if (!defines.Contains(arg) && (stack.Count == 0 || stack.Peek().Item1)) - { - defines.Add(arg); - } - } - else if (directive == "undefine") - { - if (stack.Count == 0 || stack.Peek().Item1) - { - defines.Remove(arg); - } - } else if (directive == "if") { - var evalResult = EvaluateDefine(arg.Trim(), defines); + var evalResult = true; var isEmitting = stack.Count == 0 || stack.Peek().Item1; stack.Push(new Tuple(isEmitting && evalResult, isEmitting && !evalResult)); } else if (directive == "elif") { - var evalResult = EvaluateDefine(arg, defines); + namespaceModificationFound |= CheckForNamespaceModification(namespaceScopeStack, stack.Count); + var evalResult = true; var elseEmitting = stack.Peek().Item2; stack.Pop(); stack.Push(new Tuple(elseEmitting && evalResult, elseEmitting && !evalResult)); } } + if (namespaceModificationFound) + s_LogWarningAction( + $"A namespace modification was detected. Namespace modification with preprocessor directives is not supported. Please ensure that all directives do not change the namespaces of types."); + return stringBuilder.ToString(); } @@ -260,7 +307,12 @@ public static bool EvaluateDefine(string expr, ICollection defines) else if (match.Groups[3].Value == "true" || match.Groups[3].Value == "false") res.Add((match.Groups[3].Value == "true").ToString().ToLower()); else if (match.Groups[3].Success) - res.Add(defines.Contains(match.Groups[3].Value).ToString().ToLower()); + { + if (defines.Contains(match.Groups[3].Value)) + res.Add("true"); + else + res.Add("false"); + } else if (match.Groups[4].Success) res.Add(match.Groups[4].Value); } diff --git a/Editor/Mono/Scripting/ScriptCompilation/CompilationPipeline.cs b/Editor/Mono/Scripting/ScriptCompilation/CompilationPipeline.cs index c209297667..a3270f0561 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/CompilationPipeline.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/CompilationPipeline.cs @@ -4,8 +4,10 @@ using System; using System.Collections.Generic; +using System.IO; using UnityEditor.Scripting.ScriptCompilation; using System.Linq; +using UnityEditor.Scripting.Compilers; using sc = UnityEditor.Scripting.ScriptCompilation; using UnityEditorInternal; @@ -21,10 +23,14 @@ public enum AssemblyFlags public class ScriptCompilerOptions { public bool AllowUnsafeCode { get; set; } + public ApiCompatibilityLevel ApiCompatibilityLevel { get; set; } + public string[] ResponseFiles { get; set; } public ScriptCompilerOptions() { AllowUnsafeCode = false; + ApiCompatibilityLevel = ApiCompatibilityLevel.NET_4_6; + ResponseFiles = new string[0]; } } @@ -91,6 +97,15 @@ public Assembly(string name, } } + public class ResponseFileData + { + public string[] Defines; + public string[] FullPathReferences; + public string[] Errors; + public string[] OtherArguments; + public bool Unsafe; + } + public struct AssemblyDefinitionPlatform { public string Name { get; private set; } @@ -174,6 +189,16 @@ internal static void SubscribeToEvents(EditorCompilation editorCompilation) }; } + public static string[] GetSystemAssemblyDirectories(ApiCompatibilityLevel apiCompatibilityLevel) + { + return MonoLibraryHelpers.GetSystemReferenceDirectories(apiCompatibilityLevel); + } + + public static ResponseFileData ParseResponseFile(string relativePath, string projectDirectory, string[] systemReferenceDirectories) + { + return ScriptCompilerBase.ParseResponseFileFromFile(relativePath, projectDirectory, systemReferenceDirectories); + } + public static Assembly[] GetAssemblies() { return GetAssemblies(AssembliesType.Editor); @@ -186,9 +211,9 @@ public static Assembly[] GetAssemblies(AssembliesType assembliesType) switch (assembliesType) { case AssembliesType.Editor: - return GetEditorAssemblies(EditorCompilationInterface.Instance, options); + return GetEditorAssemblies(EditorCompilationInterface.Instance, options, null); case AssembliesType.Player: - return GetPlayerAssemblies(EditorCompilationInterface.Instance, options); + return GetPlayerAssemblies(EditorCompilationInterface.Instance, options, null); default: throw new ArgumentOutOfRangeException("assembliesType"); } @@ -318,21 +343,23 @@ internal static string GetPrecompiledAssemblyPathFromAssemblyName(string assembl return null; } - internal static Assembly[] GetEditorAssemblies(EditorCompilation editorCompilation, EditorScriptCompilationOptions additionalOptions) + internal static Assembly[] GetEditorAssemblies(EditorCompilation editorCompilation, EditorScriptCompilationOptions additionalOptions, string[] defines) { - var scriptAssemblies = editorCompilation.GetAllEditorScriptAssemblies(additionalOptions); + var scriptAssemblies = editorCompilation.GetAllEditorScriptAssemblies(additionalOptions, defines); return ToAssemblies(scriptAssemblies); } - internal static Assembly[] GetPlayerAssemblies(EditorCompilation editorCompilation, EditorScriptCompilationOptions options) + internal static Assembly[] GetPlayerAssemblies(EditorCompilation editorCompilation, EditorScriptCompilationOptions options, string[] defines) { + options |= EditorScriptCompilationOptions.BuildingIncludingTestAssemblies; + var group = EditorUserBuildSettings.activeBuildTargetGroup; var target = EditorUserBuildSettings.activeBuildTarget; PrecompiledAssembly[] unityAssemblies = InternalEditorUtility.GetUnityAssemblies(false, group, target); PrecompiledAssembly[] precompiledAssemblies = InternalEditorUtility.GetPrecompiledAssemblies(false, group, target); - var scriptAssemblies = editorCompilation.GetAllScriptAssemblies(options, unityAssemblies, precompiledAssemblies); + var scriptAssemblies = editorCompilation.GetAllScriptAssemblies(options, unityAssemblies, precompiledAssemblies, defines); return ToAssemblies(scriptAssemblies); } @@ -356,6 +383,7 @@ internal static Assembly[] ToAssemblies(ScriptAssembly[] scriptAssemblies) flags |= AssemblyFlags.EditorAssembly; var compilerOptions = scriptAssembly.CompilerOptions; + compilerOptions.ResponseFiles = scriptAssembly.GetResponseFiles(); assemblies[i] = new Assembly(name, outputPath, @@ -375,7 +403,7 @@ internal static Assembly[] ToAssemblies(ScriptAssembly[] scriptAssemblies) for (int i = 0; i < scriptAssemblies.Length; ++i) { var scriptAssembly = scriptAssemblies[i]; - var assemblyReferences = scriptAssembly.ScriptAssemblyReferences.Select(a => scriptAssemblyToAssembly[a]).ToArray(); + var assemblyReferences = scriptAssembly.ScriptAssemblyReferences.Select(a => scriptAssemblyToAssembly[a]).Where(a => !IsInternalPlugin(a.outputPath)).ToArray(); assemblies[i].assemblyReferences = assemblyReferences; } @@ -384,6 +412,16 @@ internal static Assembly[] ToAssemblies(ScriptAssembly[] scriptAssemblies) return assemblies; } + static bool IsInternalPlugin(string fullReference) + { + if (AssemblyHelper.IsInternalAssembly(fullReference)) + { + if (!Modules.ModuleUtils.GetAdditionalReferencesForEditorCsharpProject().Contains(fullReference)) + return true; + } + return false; + } + static int CompareAssemblyDefinitionPlatformByDisplayName(AssemblyDefinitionPlatform p1, AssemblyDefinitionPlatform p2) { return string.Compare(p1.DisplayName, p2.DisplayName, StringComparison.OrdinalIgnoreCase); diff --git a/Editor/Mono/Scripting/ScriptCompilation/CustomScriptAssembly.cs b/Editor/Mono/Scripting/ScriptCompilation/CustomScriptAssembly.cs index 66744323dd..9f827a89fb 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/CustomScriptAssembly.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/CustomScriptAssembly.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using UnityEditor.Compilation; using UnityEditor; @@ -63,6 +64,15 @@ class CustomScriptAssemblyData public VersionDefine[] versionDefines; public static CustomScriptAssemblyData FromJson(string json) + { + var assemblyData = FromJsonNoFieldValidation(json); + + assemblyData.ValidateFields(); + + return assemblyData; + } + + public static CustomScriptAssemblyData FromJsonNoFieldValidation(string json) { var assemblyData = new CustomScriptAssemblyWithLegacyData(); assemblyData.autoReferenced = true; @@ -73,14 +83,17 @@ public static CustomScriptAssemblyData FromJson(string json) if (assemblyData == null) throw new System.Exception("Json file does not contain an assembly definition"); - if (string.IsNullOrEmpty(assemblyData.name)) + return assemblyData; + } + + public void ValidateFields() + { + if (string.IsNullOrEmpty(name)) throw new System.Exception("Required property 'name' not set"); - if ((assemblyData.excludePlatforms != null && assemblyData.excludePlatforms.Length > 0) && - (assemblyData.includePlatforms != null && assemblyData.includePlatforms.Length > 0)) + if ((excludePlatforms != null && excludePlatforms.Length > 0) && + (includePlatforms != null && includePlatforms.Length > 0)) throw new System.Exception("Both 'excludePlatforms' and 'includePlatforms' are set."); - - return assemblyData; } public static string ToJson(CustomScriptAssemblyData data) @@ -139,6 +152,7 @@ public CustomScriptAssemblyPlatform(string name, BuildTarget buildTarget) : this } } + [DebuggerDisplay("{Name}")] class CustomScriptAssembly { public string FilePath { get; set; } @@ -151,7 +165,7 @@ class CustomScriptAssembly public CustomScriptAssemblyPlatform[] ExcludePlatforms { get; set; } public AssetPathMetaData AssetPathMetaData { get; set; } - public ScriptCompilerOptions CompilerOptions { get; set; } + public ScriptCompilerOptions CompilerOptions { get; set; } = new ScriptCompilerOptions(); public bool OverrideReferences { get; set; } public string[] PrecompiledReferences { get; set; } diff --git a/Editor/Mono/Scripting/ScriptCompilation/EditorBuildRules.cs b/Editor/Mono/Scripting/ScriptCompilation/EditorBuildRules.cs index 83fda37032..9cd414fe23 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/EditorBuildRules.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/EditorBuildRules.cs @@ -46,7 +46,7 @@ internal class TargetAssembly public string[] AdditionalPrefixes { get; set; } public Func PathFilter { get; private set; } public Func IsCompatibleFunc { get; private set; } - public List References { get; private set; } + public List References { get; set; } public List PrecompiledReferences { get; set; } public TargetAssemblyType Type { get; private set; } public string[] Defines { get; set; } @@ -274,10 +274,10 @@ public static Dictionary CreateTargetAssemblies(IEnumera { if (groupedPrecompiledAssemblies.Count() > 1) { + var pathsString = string.Join(", ", groupedPrecompiledAssemblies.Select(x => x.Path).ToArray()); + throw new PrecompiledAssemblyException( - $"Multiple precompiled assemblies with the same name {groupedPrecompiledAssemblies.Key} included for the current platform. Only one assembly with the same name is allowed per platform. Assembly path: {{0}}", - groupedPrecompiledAssemblies.Select(x => x.Path).ToArray() - ); + $"Multiple precompiled assemblies with the same name {groupedPrecompiledAssemblies.Key} included for the current platform. Only one assembly with the same name is allowed per platform. Assembly paths: {pathsString}"); } nameToPrecompiledAssemblies.Add(groupedPrecompiledAssemblies.Key, groupedPrecompiledAssemblies.Single()); } @@ -601,13 +601,6 @@ internal static ScriptAssembly[] ToScriptAssemblies(IDictionary x.VersionMetaDatas ?? new AssetPathVersionMetaData[0]) .Distinct(assetPathVersionMetaDataComparer) .ToDictionary(x => x.Name, x => x.Version); + UpdateCustomTargetAssembliesAssetPathsMetaData(customScriptAssemblies, assetPathMetaDatas, forceUpdate: true); } internal AssetPathMetaData[] GetAssetPathsMetaData() @@ -659,7 +660,7 @@ public static Exception[] UpdateCustomScriptAssemblies(CustomScriptAssembly[] cu AssetPathMetaData[] assetPathsMetaData) { var asmrefLookup = customScriptAssemblyReferences.ToLookup(x => x.Reference); - var exceptions = new List(); + // Add AdditionalPrefixes foreach (var assembly in customScriptAssemblies) @@ -670,49 +671,60 @@ public static Exception[] UpdateCustomScriptAssemblies(CustomScriptAssembly[] cu assembly.AdditionalPrefixes = foundAsmRefs.Any() ? foundAsmRefs.Select(ar => ar.PathPrefix).ToArray() : null; } - // Add AssetPathMetaData - if (assetPathsMetaData != null) + var exceptions = UpdateCustomTargetAssembliesAssetPathsMetaData(customScriptAssemblies, assetPathsMetaData); + return exceptions.ToArray(); + } + + static Exception[] UpdateCustomTargetAssembliesAssetPathsMetaData(CustomScriptAssembly[] customScriptAssemblies, + AssetPathMetaData[] assetPathsMetaData, bool forceUpdate = false) + { + if (assetPathsMetaData == null) { - var assetMetaDataPaths = new string[assetPathsMetaData.Length]; - var lowerAssetMetaDataPaths = new string[assetPathsMetaData.Length]; + return new Exception[0]; + } - for (int i = 0; i < assetPathsMetaData.Length; ++i) + var exceptions = new List(); + var assetMetaDataPaths = new string[assetPathsMetaData.Length]; + var lowerAssetMetaDataPaths = new string[assetPathsMetaData.Length]; + + for (int i = 0; i < assetPathsMetaData.Length; ++i) + { + var assetPathMetaData = assetPathsMetaData[i]; + assetMetaDataPaths[i] = AssetPath.ReplaceSeparators(assetPathMetaData.DirectoryPath + AssetPath.Separator); + lowerAssetMetaDataPaths[i] = Utility.FastToLower(assetMetaDataPaths[i]); + } + + foreach (var assembly in customScriptAssemblies) + { + if (assembly.AssetPathMetaData != null && !forceUpdate) { - var assetPathMetaData = assetPathsMetaData[i]; - assetMetaDataPaths[i] = AssetPath.ReplaceSeparators(assetPathMetaData.DirectoryPath + AssetPath.Separator); - lowerAssetMetaDataPaths[i] = Utility.FastToLower(assetMetaDataPaths[i]); + continue; } - foreach (var assembly in customScriptAssemblies) + try { - try + for (int i = 0; i < assetMetaDataPaths.Length; ++i) { - if (assembly.AssetPathMetaData == null) + var path = assetMetaDataPaths[i]; + var lowerPath = lowerAssetMetaDataPaths[i]; + + if (Utility.FastStartsWith(assembly.PathPrefix, path, lowerPath)) { - for (int i = 0; i < assetMetaDataPaths.Length; ++i) - { - var path = assetMetaDataPaths[i]; - var lowerPath = lowerAssetMetaDataPaths[i]; - - if (Utility.FastStartsWith(assembly.PathPrefix, path, lowerPath)) - { - assembly.AssetPathMetaData = assetPathsMetaData[i]; - break; - } - } + assembly.AssetPathMetaData = assetPathsMetaData[i]; + break; } } - catch (Exception e) - { - exceptions.Add(e); - } + } + catch (Exception e) + { + exceptions.Add(e); } } return exceptions.ToArray(); } - Exception[] UpdateCustomTargetAssemblies() + Exception[] UpdateCustomTargetAssemblies(bool forceUpdateAssetMetadata = false) { var exceptions = UpdateCustomScriptAssemblies(customScriptAssemblies, customScriptAssemblyReferences, m_AssetPathsMetaData); @@ -1034,7 +1046,7 @@ public Exception[] SetAllCustomScriptAssemblyJsonContents(string[] paths, string if (references.Count() != references.Distinct().Count()) { - var duplicateRefs = references.GroupBy(r => r).Where(g => g.Count() > 0).Select(g => g.Key) + var duplicateRefs = references.GroupBy(r => r).Where(g => g.Count() > 1).Select(g => g.Key) .ToArray(); var duplicateRefsString = string.Join(",", duplicateRefs); @@ -1571,15 +1583,22 @@ ScriptAssemblySettings CreateScriptAssemblySettings(BuildTargetGroup buildTarget if ((options & EditorScriptCompilationOptions.BuildingPredefinedAssembliesAllowUnsafeCode) == EditorScriptCompilationOptions.BuildingPredefinedAssembliesAllowUnsafeCode) predefinedAssembliesCompilerOptions.AllowUnsafeCode = true; + predefinedAssembliesCompilerOptions.ApiCompatibilityLevel = PlayerSettings.GetApiCompatibilityLevel(buildTargetGroup); + + ICompilationExtension compilationExtension = null; + if ((options & EditorScriptCompilationOptions.BuildingForEditor) == 0) + { + compilationExtension = ModuleManager.FindPlatformSupportModule(ModuleManager.GetTargetStringFromBuildTarget(buildTarget))?.CreateCompilationExtension(); + } var settings = new ScriptAssemblySettings { BuildTarget = buildTarget, BuildTargetGroup = buildTargetGroup, OutputDirectory = GetCompileScriptsOutputDirectory(), - ApiCompatibilityLevel = PlayerSettings.GetApiCompatibilityLevel(buildTargetGroup), CompilationOptions = options, PredefinedAssembliesCompilerOptions = predefinedAssembliesCompilerOptions, + CompilationExtension = compilationExtension }; return settings; @@ -1774,7 +1793,7 @@ public TargetAssemblyInfo[] GetTargetAssembliesWithScripts(ScriptAssemblySetting public ScriptAssembly[] GetAllScriptAssembliesForLanguage(EditorScriptCompilationOptions additionalOptions) where T : SupportedLanguage { - var assemblies = GetAllScriptAssemblies(EditorScriptCompilationOptions.BuildingForEditor).Where(a => a.Language.GetType() == typeof(T)).ToArray(); + var assemblies = GetAllScriptAssemblies(EditorScriptCompilationOptions.BuildingForEditor, null).Where(a => a.Language.GetType() == typeof(T)).ToArray(); return assemblies; } @@ -1821,18 +1840,28 @@ public EditorBuildRules.TargetAssembly GetTargetAssemblyDetails(string scriptPat public ScriptAssembly[] GetAllEditorScriptAssemblies(EditorScriptCompilationOptions additionalOptions) { - return GetAllScriptAssemblies(EditorScriptCompilationOptions.BuildingForEditor | EditorScriptCompilationOptions.BuildingIncludingTestAssemblies | additionalOptions); + return GetAllScriptAssemblies(EditorScriptCompilationOptions.BuildingForEditor | EditorScriptCompilationOptions.BuildingIncludingTestAssemblies | additionalOptions, null); } - public ScriptAssembly[] GetAllScriptAssemblies(EditorScriptCompilationOptions options) + public ScriptAssembly[] GetAllEditorScriptAssemblies(EditorScriptCompilationOptions additionalOptions, string[] defines) { - return GetAllScriptAssemblies(options, unityAssemblies, precompiledAssemblies); + return GetAllScriptAssemblies(EditorScriptCompilationOptions.BuildingForEditor | EditorScriptCompilationOptions.BuildingIncludingTestAssemblies | additionalOptions, defines); } - public ScriptAssembly[] GetAllScriptAssemblies(EditorScriptCompilationOptions options, PrecompiledAssembly[] unityAssembliesArg, PrecompiledAssembly[] precompiledAssembliesArg) + public ScriptAssembly[] GetAllScriptAssemblies(EditorScriptCompilationOptions options, string[] defines) + { + return GetAllScriptAssemblies(options, unityAssemblies, precompiledAssemblies, defines); + } + + public ScriptAssembly[] GetAllScriptAssemblies(EditorScriptCompilationOptions options, PrecompiledAssembly[] unityAssembliesArg, PrecompiledAssembly[] precompiledAssembliesArg, string[] defines) { ScriptAssemblySettings settings = CreateEditorScriptAssemblySettings(options); + if (defines != null) + { + settings.ExtraGeneralDefines = defines; + } + UpdateAllTargetAssemblyDefines(customTargetAssemblies, EditorBuildRules.GetPredefinedTargetAssemblies(), m_AllDistinctVersionMetaDatas, settings); var assemblies = new EditorBuildRules.CompilationAssemblies @@ -1869,7 +1898,7 @@ private static void UpdateAllTargetAssemblyDefines(IDictionary(); diff --git a/Editor/Mono/Scripting/ScriptCompilation/PlatformSupportModuleHelpers.cs b/Editor/Mono/Scripting/ScriptCompilation/PlatformSupportModuleHelpers.cs new file mode 100644 index 0000000000..2f40d6ac32 --- /dev/null +++ b/Editor/Mono/Scripting/ScriptCompilation/PlatformSupportModuleHelpers.cs @@ -0,0 +1,38 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using System; +using System.Linq; +using UnityEditor.Modules; + +namespace UnityEditor.Scripting.ScriptCompilation +{ + static class PlatformSupportModuleHelpers + { + public static void AddAdditionalPlatformSupportData(ICompilationExtension compilationExtension, ref ScriptAssembly scriptAssembly) + { + if (compilationExtension == null) + { + return; + } + + scriptAssembly.Defines = AddAdditionalToArray(scriptAssembly.Defines, compilationExtension.GetAdditionalDefines().ToArray()); + scriptAssembly.References = AddAdditionalToArray(scriptAssembly.References, compilationExtension.GetAdditionalAssemblyReferences() + .Concat(compilationExtension.GetWindowsMetadataReferences()).ToArray()); + scriptAssembly.Files = AddAdditionalToArray(scriptAssembly.Files, compilationExtension.GetAdditionalSourceFiles().ToArray()); + } + + private static string[] AddAdditionalToArray(string[] source, string[] extras) + { + if (extras == null) + { + return source; + } + var destinationArray = new string[source.Length + extras.Length]; + Array.Copy(source, destinationArray, source.Length); + Array.Copy(extras, 0, destinationArray, source.Length, extras.Length); + return destinationArray; + } + } +} diff --git a/Editor/Mono/Scripting/ScriptCompilation/ScriptAssembly.cs b/Editor/Mono/Scripting/ScriptCompilation/ScriptAssembly.cs index 755cff5b63..91bb724c20 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/ScriptAssembly.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/ScriptAssembly.cs @@ -2,10 +2,12 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License +using System; using System.Collections.Generic; using System.Linq; using UnityEditor.Scripting.Compilers; using UnityEditor.Compilation; +using UnityEditor.Modules; namespace UnityEditor.Scripting.ScriptCompilation { @@ -15,11 +17,11 @@ class ScriptAssemblySettings public BuildTarget BuildTarget { get; set; } public BuildTargetGroup BuildTargetGroup { get; set; } public string OutputDirectory { get; set; } - public ApiCompatibilityLevel ApiCompatibilityLevel { get; set; } public EditorScriptCompilationOptions CompilationOptions { get; set; } public ScriptCompilerOptions PredefinedAssembliesCompilerOptions { get; set; } public string[] ExtraGeneralDefines { get; set; } + public ICompilationExtension CompilationExtension { get; set; } public ScriptAssemblySettings() @@ -47,7 +49,6 @@ class ScriptAssembly public AssemblyFlags Flags { get; set; } public BuildTarget BuildTarget { get; set; } public SupportedLanguage Language { get; set; } - public ApiCompatibilityLevel ApiCompatibilityLevel { get; set; } public string Filename { get; set; } public string OutputDirectory { get; set; } @@ -96,12 +97,22 @@ public MonoIsland ToMonoIsland(EditorScriptCompilationOptions options, string bu buildingForEditor, developmentBuild, CompilerOptions.AllowUnsafeCode, - ApiCompatibilityLevel, + CompilerOptions.ApiCompatibilityLevel, Files, referencesArray, Defines, outputPath, reposeFiles.ToArray()); } + + public string[] GetResponseFiles() + { + if (Language == null) + { + throw new ArgumentException("Language: not set on ScriptAssembly. Cannot resolve responsefiles"); + } + var responseFileProvider = Language.CreateResponseFileProvider(); + return responseFileProvider.Get(OriginPath).ToArray(); + } } } diff --git a/Editor/Mono/Scripting/ScriptCompilation/SemVersion.cs b/Editor/Mono/Scripting/ScriptCompilation/SemVersion.cs index 2e02640757..c8332c2b62 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/SemVersion.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/SemVersion.cs @@ -129,7 +129,10 @@ private static int CompareExtension(string current, string other, bool lower = f if (currentPartIsNumber && otherPartIsNumber) { result = currentNumber.CompareTo(otherNumber); - if (result != 0) return currentPart.CompareTo(otherNumber); + if (result != 0) + { + return result; + } } else { @@ -145,10 +148,11 @@ private static int CompareExtension(string current, string other, bool lower = f result = string.CompareOrdinal(currentPart, otherPart); if (result != 0) + { return result; + } } } - return currentParts.Length.CompareTo(otherParts.Length); } diff --git a/Editor/Mono/SearchUtility.cs b/Editor/Mono/SearchUtility.cs index 9b36997ade..149ef0ac18 100644 --- a/Editor/Mono/SearchUtility.cs +++ b/Editor/Mono/SearchUtility.cs @@ -187,14 +187,18 @@ internal static bool CheckForKeyWords(string searchString, SearchFilter filter, if (count < 0 || quote2 == -1) count = searchString.Length - startIndex; - // Strip filepath from quotes - assetPath = "Assets/" + searchString.Substring(startIndex, count); + // Strip filepath from quotes, don't prefix with Assets/, we need to support Packages/ (https://fogbugz.unity3d.com/f/cases/1161019/) + assetPath = searchString.Substring(startIndex, count); } else - // Otherwise use string from colon to end - assetPath = "Assets/" + searchString.Substring(firstColon + 1); + // Otherwise use string from colon to end, don't prefix with Assets/, we need to support Packages/ (https://fogbugz.unity3d.com/f/cases/1161019/) + assetPath = searchString.Substring(firstColon + 1); Object obj = AssetDatabase.LoadMainAssetAtPath(assetPath); + if (obj == null) + // Backward compatibility, in case Assets/ was strip from path + obj = AssetDatabase.LoadMainAssetAtPath("Assets/" + assetPath); + if (obj != null) instanceID = obj.GetInstanceID(); //else diff --git a/Editor/Mono/SelectionCommands/SelectionCommands.cs b/Editor/Mono/SelectionCommands/SelectionCommands.cs index f0667c2878..2476b8da8a 100644 --- a/Editor/Mono/SelectionCommands/SelectionCommands.cs +++ b/Editor/Mono/SelectionCommands/SelectionCommands.cs @@ -41,5 +41,17 @@ internal static void DeleteSelectedAssetsShortcut() { InternalEditorUtility.ExecuteCommandOnKeyWindow(EventCommandNames.Delete); } + + [Shortcut("Edit/CopyInsert", KeyCode.Insert, ShortcutModifiers.Action, displayName = "Copy Insert Selection")] + internal static void CopyInsertSelection() + { + InternalEditorUtility.ExecuteCommandOnKeyWindow(EventCommandNames.Copy); + } + + [Shortcut("Edit/PasteInsert", KeyCode.Insert, ShortcutModifiers.Shift, displayName = "Paste Insert Selection")] + internal static void PasteInsertSelection() + { + InternalEditorUtility.ExecuteCommandOnKeyWindow(EventCommandNames.Paste); + } } } diff --git a/Editor/Mono/SerializedProperty.bindings.cs b/Editor/Mono/SerializedProperty.bindings.cs index 51462b06d4..f3e746487d 100644 --- a/Editor/Mono/SerializedProperty.bindings.cs +++ b/Editor/Mono/SerializedProperty.bindings.cs @@ -881,8 +881,8 @@ public int objectReferenceInstanceIDValue { get { - UnityObject obj = objectReferenceValue; - return obj ? obj.GetInstanceID() : 0; + Verify(VerifyFlags.IteratorNotAtEnd); + return GetPPtrValueFromInstanceIDInternal(); } set { @@ -891,6 +891,9 @@ public int objectReferenceInstanceIDValue } } + [NativeName("GetPPtrInstanceID")] + private extern int GetPPtrValueFromInstanceIDInternal(); + [FreeFunction(Name = "SerializedPropertyBindings::SetPPtrValueFromInstanceIDInternal", HasExplicitThis = true)] private extern void SetPPtrValueFromInstanceIDInternal(int instanceID); diff --git a/Editor/Mono/SerializedProperty/SerializedPropertyTable.cs b/Editor/Mono/SerializedProperty/SerializedPropertyTable.cs index dc00229fa2..3fbd034cf9 100644 --- a/Editor/Mono/SerializedProperty/SerializedPropertyTable.cs +++ b/Editor/Mono/SerializedProperty/SerializedPropertyTable.cs @@ -135,7 +135,10 @@ public void OnGUI() r = GUILayoutUtility.GetRect(0, float.MaxValue, 0, float.MaxValue); if (Event.current.type == EventType.Layout) + { + Profiler.EndSample(); return; + } float windowWidth = r.width; float tableHeight = r.height - m_FilterHeight - (dragHandleEnabled ? m_DragHeight : 0); diff --git a/Editor/Mono/SerializedProperty/SerializedPropertyTreeView.cs b/Editor/Mono/SerializedProperty/SerializedPropertyTreeView.cs index 5bb3bf8fb0..0c3f218b86 100644 --- a/Editor/Mono/SerializedProperty/SerializedPropertyTreeView.cs +++ b/Editor/Mono/SerializedProperty/SerializedPropertyTreeView.cs @@ -482,8 +482,8 @@ void CellGUI(Rect cellRect, SerializedPropertyItem item, int columnIndex, ref Ro } } } - Profiler.EndSample(); } + Profiler.EndSample(); } private static bool IsEditable(Object target) diff --git a/Editor/Mono/SettingsWindow/FogEditor.cs b/Editor/Mono/SettingsWindow/FogEditor.cs index 9efc2275e1..4c8d788b9f 100644 --- a/Editor/Mono/SettingsWindow/FogEditor.cs +++ b/Editor/Mono/SettingsWindow/FogEditor.cs @@ -16,7 +16,7 @@ internal class Styles public static readonly GUIContent FogLinearStart = EditorGUIUtility.TrTextContent("Start", "Controls the distance from the camera where the fog will start in the Scene."); public static readonly GUIContent FogLinearEnd = EditorGUIUtility.TrTextContent("End", "Controls the distance from the camera where the fog will completely obscure objects in the Scene."); public static readonly GUIContent FogEnable = EditorGUIUtility.TrTextContent("Fog", "Specifies whether fog is used in the Scene or not."); - public static readonly GUIContent FogColor = EditorGUIUtility.TrTextContent("Color", "Controls the color of that fog drawn in the Scene."); + public static readonly GUIContent FogColor = EditorGUIUtility.TrTextContent("Color", "Controls the color of the fog drawn in the Scene."); public static readonly GUIContent FogMode = EditorGUIUtility.TrTextContent("Mode", "Controls the mathematical function determining the way fog accumulates with distance from the camera. Options are Linear, Exponential, and Exponential Squared."); } diff --git a/Editor/Mono/SettingsWindow/GraphicsSettingsEditors.cs b/Editor/Mono/SettingsWindow/GraphicsSettingsEditors.cs index de9d885c51..db41b4dd2b 100644 --- a/Editor/Mono/SettingsWindow/GraphicsSettingsEditors.cs +++ b/Editor/Mono/SettingsWindow/GraphicsSettingsEditors.cs @@ -248,7 +248,7 @@ internal partial class Styles public static readonly GUIContent lightmapPlain = EditorGUIUtility.TrTextContent("Baked Non-Directional", "Include support for baked non-directional lightmaps."); public static readonly GUIContent lightmapDirCombined = EditorGUIUtility.TrTextContent("Baked Directional", "Include support for baked directional lightmaps."); public static readonly GUIContent lightmapKeepShadowMask = EditorGUIUtility.TrTextContent("Baked Shadowmask", "Include support for baked shadow occlusion."); - public static readonly GUIContent lightmapKeepSubtractive = EditorGUIUtility.TrTextContent("Baked Subtractive", "Include support for baked substractive lightmaps."); + public static readonly GUIContent lightmapKeepSubtractive = EditorGUIUtility.TrTextContent("Baked Subtractive", "Include support for baked subtractive lightmaps."); public static readonly GUIContent lightmapDynamicPlain = EditorGUIUtility.TrTextContent("Realtime Non-Directional", "Include support for realtime non-directional lightmaps."); public static readonly GUIContent lightmapDynamicDirCombined = EditorGUIUtility.TrTextContent("Realtime Directional", "Include support for realtime directional lightmaps."); public static readonly GUIContent lightmapFromScene = EditorGUIUtility.TrTextContent("Import From Current Scene", "Calculate lightmap modes used by the current scene."); @@ -584,7 +584,7 @@ internal partial class Styles public static readonly GUIContent reflectionProbeBlending = EditorGUIUtility.TrTextContent("Reflection Probes Blending"); public static readonly GUIContent detailNormalMap = EditorGUIUtility.TrTextContent("Detail Normal Map"); public static readonly GUIContent cascadedShadowMaps = EditorGUIUtility.TrTextContent("Cascaded Shadows"); - public static readonly GUIContent prefer32BitShadowMaps = EditorGUIUtility.TrTextContent("Prefer 32 bit shadow maps"); + public static readonly GUIContent prefer32BitShadowMaps = EditorGUIUtility.TrTextContent("Prefer 32-bit shadow maps"); public static readonly GUIContent semitransparentShadows = EditorGUIUtility.TrTextContent("Enable Semitransparent Shadows"); public static readonly GUIContent enableLPPV = EditorGUIUtility.TrTextContent("Enable Light Probe Proxy Volume"); public static readonly GUIContent renderingPath = EditorGUIUtility.TrTextContent("Rendering Path"); diff --git a/Editor/Mono/Sprites/SpriteUtilityWindow.cs b/Editor/Mono/Sprites/SpriteUtilityWindow.cs index e3396ce32a..0a97a909ba 100644 --- a/Editor/Mono/Sprites/SpriteUtilityWindow.cs +++ b/Editor/Mono/Sprites/SpriteUtilityWindow.cs @@ -24,7 +24,9 @@ protected class Styles public readonly GUIStyle preBackground = "preBackground"; public readonly GUIStyle pivotdotactive = "U2D.pivotDotActive"; public readonly GUIStyle pivotdot = "U2D.pivotDot"; - + public static readonly GUIContent noSpriteEditorWindowTitle = EditorGUIUtility.TrTextContent("Sprite Editor Window"); + public static readonly GUIContent noSpriteEditorWindow = EditorGUIUtility.TrTextContent("No Sprite Editor Window registered. Please download 2D Sprite package from Package Manager."); + public static readonly GUIContent okText = EditorGUIUtility.TrTextContent("OK"); public readonly GUIStyle dragBorderdot = new GUIStyle(); public readonly GUIStyle dragBorderDotActive = new GUIStyle(); @@ -392,7 +394,7 @@ internal static bool ShowSpriteEditorWindow() static Func showSpriteEditorWindow = () => { - Debug.Log("No Sprite Editor Window is registered."); + EditorUtility.DisplayDialog(Styles.noSpriteEditorWindowTitle.text, Styles.noSpriteEditorWindow.text, Styles.okText.text); return false; }; } // class diff --git a/Editor/Mono/SyncProject.cs b/Editor/Mono/SyncProject.cs index 48c93894f9..ffa28789c3 100644 --- a/Editor/Mono/SyncProject.cs +++ b/Editor/Mono/SyncProject.cs @@ -12,6 +12,7 @@ using UnityEngine; using UnityEngine.Scripting; using UnityEditorInternal; +using Unity.CodeEditor; namespace UnityEditor { @@ -40,7 +41,7 @@ public VisualStudioPath(string path, string edition = "") } [InitializeOnLoad] - internal class SyncVS : AssetPostprocessor + internal partial class SyncVS : AssetPostprocessor { static bool s_AlreadySyncedThisDomainReload; @@ -56,16 +57,6 @@ static SyncVS() Console.WriteLine("Error detecting Visual Studio installations: {0}{1}{2}", ex.Message, Environment.NewLine, ex.StackTrace); InstalledVisualStudios = new Dictionary(); } - - SetVisualStudioAsEditorIfNoEditorWasSet(); - } - - private static void SetVisualStudioAsEditorIfNoEditorWasSet() - { - var externalEditor = EditorPrefs.GetString("kScriptsDefaultApp"); - var bestVisualStudio = FindBestVisualStudio(); - if (externalEditor == "" && bestVisualStudio != null) - EditorPrefs.SetString("kScriptsDefaultApp", bestVisualStudio); } public static string FindBestVisualStudio() @@ -74,7 +65,7 @@ public static string FindBestVisualStudio() return vs == null ? null : vs.Last().Path; } - private static readonly SolutionSynchronizer Synchronizer; + internal static readonly SolutionSynchronizer Synchronizer; internal static Dictionary InstalledVisualStudios { get; private set; } internal class SolutionSynchronizationSettings : DefaultSolutionSynchronizationSettings @@ -83,7 +74,7 @@ public override int VisualStudioVersion { get { - var vs = ScriptEditorUtility.GetExternalScriptEditor(); + var vs = CodeEditor.CurrentEditorInstallation; if (InstalledVisualStudios.ContainsKey(UnityEditor.VisualStudioVersion.VisualStudio2008) && (vs != String.Empty) && PathsAreEquivalent(InstalledVisualStudios[UnityEditor.VisualStudioVersion.VisualStudio2008].Last().Path, vs)) @@ -160,7 +151,8 @@ public void OnActiveBuildTargetChanged(BuildTarget oldTarget, BuildTarget newTar [RequiredByNativeCode] public static void SyncVisualStudioProjectIfItAlreadyExists() { - if (Synchronizer.SolutionExists()) + #pragma warning disable 618 + if (Synchronizer.SolutionExists() && ScriptEditorUtility.GetScriptEditorFromPath(CodeEditor.CurrentEditorInstallation) != ScriptEditorUtility.ScriptEditor.Other) { Synchronizer.Sync(); } @@ -177,21 +169,6 @@ public static void PostprocessSyncProject( Synchronizer.SyncIfNeeded(addedAssets.Union(deletedAssets.Union(movedAssets.Union(movedFromAssetPaths))), importedAssets); } - [MenuItem("Assets/Open C# Project")] - static void SyncAndOpenSolution() - { - SyncSolution(); - OpenProjectFileUnlessInBatchMode(); - } - - public static void SyncSolution() - { - // Ensure that the mono islands are up-to-date - AssetDatabase.Refresh(); - - Synchronizer.Sync(); - } - public static void SyncIfFirstFileOpenSinceDomainLoad() { if (s_AlreadySyncedThisDomainReload) @@ -201,14 +178,6 @@ public static void SyncIfFirstFileOpenSinceDomainLoad() Synchronizer.Sync(); } - private static void OpenProjectFileUnlessInBatchMode() - { - if (InternalEditorUtility.inBatchMode) - return; - - InternalEditorUtility.OpenFileAtLineExternal("", -1, -1); - } - /// /// Detects Visual Studio installations using the Windows registry /// diff --git a/Editor/Mono/SyncRiderProject.cs b/Editor/Mono/SyncRiderProject.cs deleted file mode 100644 index ab7179e363..0000000000 --- a/Editor/Mono/SyncRiderProject.cs +++ /dev/null @@ -1,275 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Microsoft.Win32; -using UnityEditorInternal; -using UnityEngine; - -namespace UnityEditor -{ - [InitializeOnLoad] - internal class SyncRiderProject - { - static SyncRiderProject() - { - ScriptEditorUtility.RegisterIde(PathCallback); - } - - static ScriptEditorUtility.Installation[] PathCallback() - { - return RiderPathLocator.GetAllRiderPaths() - .Select(riderInfo => new ScriptEditorUtility.Installation - { - Path = riderInfo.Path, - Name = riderInfo.Presentation - }) - .ToArray(); - } - } - - /// - /// This code is a modified version of the JetBrains resharper-unity plugin listed here: - /// https://github.com/JetBrains/resharper-unity/blob/master/unity/JetBrains.Rider.Unity.Editor/EditorPlugin/RiderPathLocator.cs - /// - internal static class RiderPathLocator - { - static RiderInfo[] CollectAllRiderPathsLinux() - { - var home = Environment.GetEnvironmentVariable("HOME"); - if (string.IsNullOrEmpty(home)) - return new RiderInfo[0]; - const string pathToBuildTxt = "../../build.txt"; - //$Home/.local/share/JetBrains/Toolbox/apps/Rider/ch-0/173.3994.1125/bin/rider.sh - //$Home/.local/share/JetBrains/Toolbox/apps/Rider/ch-0/.channel.settings.json - var toolboxRiderRootPath = Path.Combine(home, @".local/share/JetBrains/Toolbox/apps/Rider"); - var paths = CollectPathsFromToolbox(toolboxRiderRootPath, "bin", "rider.sh", false) - .Select(a => new RiderInfo(GetBuildNumber(Path.Combine(a, pathToBuildTxt)), a, true)).ToList(); - - - // $Home/.local/share/applications/jetbrains-rider.desktop - var shortcut = new FileInfo(Path.Combine(home, @".local/share/applications/jetbrains-rider.desktop")); - - if (shortcut.Exists) - { - var lines = File.ReadAllLines(shortcut.FullName); - foreach (var line in lines) - { - if (!line.StartsWith("Exec=\"")) - continue; - var path = line.Split('"').Where((item, index) => index == 1).SingleOrDefault(); - if (string.IsNullOrEmpty(path)) - continue; - var buildTxtPath = Path.Combine(path, pathToBuildTxt); - var buildNumber = GetBuildNumber(buildTxtPath); - if (paths.Any(a => a.Path == path)) // avoid adding similar build as from toolbox - continue; - paths.Add(new RiderInfo(buildNumber, path, false)); - } - } - - return paths.ToArray(); - } - - static RiderInfo[] CollectRiderInfosMac() - { - var pathToBuildTxt = "Contents/Resources/build.txt"; - - // "/Applications/*Rider*.app" - var folder = new DirectoryInfo("/Applications"); - var results = folder.GetDirectories("*Rider*.app") - .Select(a => new RiderInfo(GetBuildNumber(Path.Combine(a.FullName, pathToBuildTxt)), a.FullName, false)) - .ToList(); - - // /Users/user/Library/Application Support/JetBrains/Toolbox/apps/Rider/ch-1/181.3870.267/Rider EAP.app - var home = Environment.GetEnvironmentVariable("HOME"); - if (!string.IsNullOrEmpty(home)) - { - var toolboxRiderRootPath = - Path.Combine(home, @"Library/Application Support/JetBrains/Toolbox/apps/Rider"); - var paths = CollectPathsFromToolbox(toolboxRiderRootPath, "", "Rider*.app", true) - .Select(a => new RiderInfo(GetBuildNumber(Path.Combine(a, pathToBuildTxt)), a, true)); - results.AddRange(paths); - } - - return results.ToArray(); - } - - static string GetBuildNumber(string path) - { - var file = new FileInfo(path); - if (file.Exists) - return File.ReadAllText(file.FullName); - return string.Empty; - } - - static RiderInfo[] CollectRiderInfosWindows() - { - var pathToBuildTxt = "../../build.txt"; - - var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); - var toolboxRiderRootPath = Path.Combine(localAppData, @"JetBrains\Toolbox\apps\Rider"); - var installPathsToolbox = - CollectPathsFromToolbox(toolboxRiderRootPath, "bin", "rider64.exe", false).ToList(); - var installInfosToolbox = installPathsToolbox - .Select(a => new RiderInfo(GetBuildNumber(Path.Combine(a, pathToBuildTxt)), a, true)).ToList(); - - var installPaths = new List(); - const string registryKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"; - CollectPathsFromRegistry(registryKey, installPaths); - const string wowRegistryKey = @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"; - CollectPathsFromRegistry(wowRegistryKey, installPaths); - - var installInfos = installPaths - .Select(a => new RiderInfo(GetBuildNumber(Path.Combine(a, pathToBuildTxt)), a, false)).ToList(); - installInfos.AddRange(installInfosToolbox); - - return installInfos.ToArray(); - } - - static void CollectPathsFromRegistry(string registryKey, List installPaths) - { - using (var key = Registry.LocalMachine.OpenSubKey(registryKey)) - { - if (key == null) return; - foreach (var subkeyName in key.GetSubKeyNames().Where(a => a.Contains("Rider"))) - { - using (var subkey = key.OpenSubKey(subkeyName)) - { - var folderObject = subkey?.GetValue("InstallLocation"); - if (folderObject == null) continue; - var folder = folderObject.ToString(); - var possiblePath = Path.Combine(folder, @"bin\rider64.exe"); - if (File.Exists(possiblePath)) - installPaths.Add(possiblePath); - } - } - } - } - - public static RiderInfo[] GetAllRiderPaths() - { - try - { - switch (SystemInfo.operatingSystemFamily) - { - case OperatingSystemFamily.Windows: - { - return CollectRiderInfosWindows(); - } - case OperatingSystemFamily.MacOSX: - { - return CollectRiderInfosMac(); - } - case OperatingSystemFamily.Linux: - { - return CollectAllRiderPathsLinux(); - } - } - } - catch (Exception e) - { - Debug.LogException(e); - } - - - return new RiderInfo[0]; - } - - static string[] CollectPathsFromToolbox( - string toolboxRiderRootPath, - string dirName, - string searchPattern, - bool isMac) - { - if (!Directory.Exists(toolboxRiderRootPath)) - return new string[0]; - - var channelFiles = Directory.GetDirectories(toolboxRiderRootPath) - .Select(b => Path.Combine(b, ".channel.settings.json")).Where(File.Exists).ToArray(); - - var paths = channelFiles.SelectMany(a => { - try - { - var channelDir = Path.GetDirectoryName(a); - var json = File.ReadAllText(a).Replace("active-application", "active_application"); - var toolbox = ToolboxInstallData.FromJson(json); - var builds = toolbox.active_application.builds; - if (builds != null && builds.Any()) - { - var build = builds.First(); - var folder = Path.Combine(Path.Combine(channelDir, build), dirName); - if (!isMac) - return new[] {Path.Combine(folder, searchPattern)}; - return new DirectoryInfo(folder).GetDirectories(searchPattern).Select(f => f.FullName); - } - - // new toolbox format doesn't have active-application block, so return all found Rider installations - return Directory.GetDirectories(channelDir) - .SelectMany(b => - { - var folder = Path.Combine(b, dirName); - if (!isMac) - return new[] {Path.Combine(folder, searchPattern)}; - return new DirectoryInfo(folder).GetDirectories(searchPattern).Select(f => f.FullName); - }) - .Where(File.Exists).ToArray(); - } - catch (Exception e) - { - Debug.LogException(e); - Debug.LogWarning("Failed to get RiderPath via .channel.settings.json"); - } - - return new string[0]; - }) - .Where(c => !string.IsNullOrEmpty(c)) - .ToArray(); - return paths; - } - - [Serializable] - class ToolboxInstallData - { - public ActiveApplication active_application = null; - - public static ToolboxInstallData FromJson(string json) - { - return JsonUtility.FromJson(json); - } - } - - [Serializable] - class ActiveApplication - { - public List builds = null; - } - - public struct RiderInfo - { - public string Presentation; - public string BuildVersion; - public string Path; - - public RiderInfo(string buildVersion, string path, bool isToolbox) - { - BuildVersion = buildVersion; - Path = new FileInfo(path).FullName; // normalize separators - - var version = string.Empty; - if (buildVersion.Length > 3) - version = buildVersion.Substring(3); - - var presentation = "Rider " + version; - if (isToolbox) - presentation += " (JetBrains Toolbox)"; - - Presentation = presentation; - } - } - } -} diff --git a/Editor/Mono/UIElements/Controls/BindingExtensions.cs b/Editor/Mono/UIElements/Controls/BindingExtensions.cs index 52aaa02c51..08e9fbf427 100644 --- a/Editor/Mono/UIElements/Controls/BindingExtensions.cs +++ b/Editor/Mono/UIElements/Controls/BindingExtensions.cs @@ -115,7 +115,14 @@ public static void Unbind(this VisualElement element) public static SerializedProperty BindProperty(this IBindable field, SerializedObject obj) { - return BindPropertyWithParent(field, new SerializedObjectUpdateWrapper(obj), null); + var property = obj?.FindProperty(field.bindingPath); + + if (property != null) + { + Bind(field as VisualElement, new SerializedObjectUpdateWrapper(obj), null); + } + + return property; } public static void BindProperty(this IBindable field, SerializedProperty property) @@ -125,7 +132,8 @@ public static void BindProperty(this IBindable field, SerializedProperty propert throw new ArgumentNullException(nameof(property)); } - DoBindProperty(field, new SerializedObjectUpdateWrapper(property.serializedObject), property); + field.bindingPath = property.propertyPath; + Bind(field as VisualElement, new SerializedObjectUpdateWrapper(property.serializedObject), null); } private static void DoBindProperty(IBindable field, SerializedObjectUpdateWrapper obj, SerializedProperty property) diff --git a/Editor/Mono/UIElements/Controls/MaskField.cs b/Editor/Mono/UIElements/Controls/MaskField.cs index 08719ccc63..ef5ace4d16 100644 --- a/Editor/Mono/UIElements/Controls/MaskField.cs +++ b/Editor/Mono/UIElements/Controls/MaskField.cs @@ -247,7 +247,7 @@ internal string GetDisplayedValue(int itemIndex) } else { - newValueToShowUser = L10n.Tr("Mixed ..."); + newValueToShowUser = L10n.Tr("Mixed..."); } break; } diff --git a/Editor/Mono/UIElements/Controls/PropertyField.cs b/Editor/Mono/UIElements/Controls/PropertyField.cs index 7f11a80cf4..4402883d47 100644 --- a/Editor/Mono/UIElements/Controls/PropertyField.cs +++ b/Editor/Mono/UIElements/Controls/PropertyField.cs @@ -100,13 +100,22 @@ private void Reset(SerializedPropertyBindEvent evt) { customPropertyGUI = new IMGUIContainer(() => { - EditorGUI.BeginChangeCheck(); - m_SerializedProperty.serializedObject.Update(); - - EditorGUILayout.PropertyField(m_SerializedProperty, true); - - m_SerializedProperty.serializedObject.ApplyModifiedProperties(); - EditorGUI.EndChangeCheck(); + var originalWideMode = InspectorElement.SetWideModeForWidth(this); + + try + { + EditorGUI.BeginChangeCheck(); + m_SerializedProperty.serializedObject.Update(); + + EditorGUILayout.PropertyField(m_SerializedProperty, true); + + m_SerializedProperty.serializedObject.ApplyModifiedProperties(); + EditorGUI.EndChangeCheck(); + } + finally + { + EditorGUIUtility.wideMode = originalWideMode; + } }); } hierarchy.Add(customPropertyGUI); @@ -159,6 +168,16 @@ private void UpdateArrayFoldout( // number of them). if (parentSerializedObject != null) parentPropertyField.Bind(parentSerializedObject); + + // Very important that we stop immediate propagation here. If we don't, + // the next handler will be FieldValueChanged() in the IBinding which + // will be operating on a stale [this target] field + // (we just killed it in our Unbind()/Bind() above). + // In turn, because we share the IBinding, this event handling will + // essentially call Unbind() one more time on the array size field + // [this.target] and the array size field will no longer work. + // See: case 1141787 + changeEvent.StopImmediatePropagation(); } private VisualElement CreateFoldout(SerializedProperty property) diff --git a/Editor/Mono/UIElements/VisualTreeAssetEditor.cs b/Editor/Mono/UIElements/VisualTreeAssetEditor.cs index 547b7c3f20..77c0fe5fc2 100644 --- a/Editor/Mono/UIElements/VisualTreeAssetEditor.cs +++ b/Editor/Mono/UIElements/VisualTreeAssetEditor.cs @@ -94,7 +94,8 @@ public void Render(VisualTreeAsset vta, Rect r, GUIStyle background) clips--; } - var desc = new RenderTextureDescriptor((int)r.width, (int)r.height, RenderTextureFormat.ARGB32, 16); + float pixelsPerPoint = EditorGUIUtility.pixelsPerPoint; + var desc = new RenderTextureDescriptor((int)(r.width * pixelsPerPoint), (int)(r.height * pixelsPerPoint), RenderTextureFormat.ARGB32, 16); var rt = RenderTexture.GetTemporary(desc); var oldRt = RenderTexture.active; RenderTexture.active = rt; diff --git a/Editor/Mono/Unsupported.bindings.cs b/Editor/Mono/Unsupported.bindings.cs index 6bd0fdd634..b637151588 100644 --- a/Editor/Mono/Unsupported.bindings.cs +++ b/Editor/Mono/Unsupported.bindings.cs @@ -78,15 +78,15 @@ public static bool IsDeveloperBuild() [FreeFunction("GetScreenManager().SetAllowCursorLock")] internal static extern void SetAllowCursorLock(bool allow, DisallowCursorLockReasons reasons); - public static bool SetOverrideRenderSettings(Scene scene) + public static bool SetOverrideLightingSettings(Scene scene) { - return SetOverrideRenderSettingsInternal(scene.handle); + return SetOverrideLightingSettingsInternal(scene.handle); } - internal static extern bool SetOverrideRenderSettingsInternal(int sceneHandle); + internal static extern bool SetOverrideLightingSettingsInternal(int sceneHandle); - public static extern void RestoreOverrideRenderSettings(); + public static extern void RestoreOverrideLightingSettings(); [FreeFunction("GetRenderSettings().SetUseFogNoDirty")] public static extern void SetRenderSettingsUseFogNoDirty(bool fog); diff --git a/Editor/Mono/Utils/Paths.cs b/Editor/Mono/Utils/Paths.cs index 23face38d5..aa4fb89e45 100644 --- a/Editor/Mono/Utils/Paths.cs +++ b/Editor/Mono/Utils/Paths.cs @@ -329,11 +329,15 @@ public static string MakeValidFileName(string unsafeFileName) { var normalizedFileName = unsafeFileName.Trim().Normalize(NormalizationForm.FormD); var stringBuilder = new StringBuilder(); - foreach (var c in normalizedFileName) + + // We need to use a TextElementEmumerator in order to support UTF16 characters that may take up more than one char(case 1169358) + TextElementEnumerator charEnum = StringInfo.GetTextElementEnumerator(normalizedFileName); + while (charEnum.MoveNext()) { - if (invalidFilenameChars.Contains(c)) + var c = charEnum.GetTextElement(); + if (c.Length == 1 && invalidFilenameChars.Contains(c[0])) continue; - var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c); + var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c, 0); if (unicodeCategory != UnicodeCategory.NonSpacingMark) stringBuilder.Append(c); } diff --git a/Editor/Mono/VersionControl/Common/VCAsset.cs b/Editor/Mono/VersionControl/Common/VCAsset.cs index 47e71f0bcf..06ee39ed73 100644 --- a/Editor/Mono/VersionControl/Common/VCAsset.cs +++ b/Editor/Mono/VersionControl/Common/VCAsset.cs @@ -138,6 +138,9 @@ internal static string AllStateToString(Asset.States state) if (IsState(state, Asset.States.ReadOnly)) sb.AppendLine("ReadOnly"); + if (IsState(state, Asset.States.Unversioned)) + sb.Append("Unversioned"); + return sb.ToString(); } diff --git a/Editor/Mono/VersionControl/Common/VCAssetModificationHooks.cs b/Editor/Mono/VersionControl/Common/VCAssetModificationHooks.cs index 7ea7cfe546..aaadfdfad8 100644 --- a/Editor/Mono/VersionControl/Common/VCAssetModificationHooks.cs +++ b/Editor/Mono/VersionControl/Common/VCAssetModificationHooks.cs @@ -2,7 +2,9 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License +using System.Collections.Generic; using System.IO; +using System.Linq; using UnityEditor; using UnityEngine; @@ -13,24 +15,18 @@ namespace UnityEditorInternal.VersionControl // Monitor the behavior of assets. This is where general unity asset operations are handled public class AssetModificationHook { - private enum CachedStatusMode + static Asset GetStatusCachedIfPossible(string fromPath, bool synchronous) { - Sync, - Async - }; - - private static Asset GetStatusCachedIfPossible(string from, CachedStatusMode mode) - { - Asset asset = Provider.CacheStatus(from); + Asset asset = Provider.CacheStatus(fromPath); if (asset == null || asset.IsState(Asset.States.Updating)) { - if (mode == CachedStatusMode.Sync) + if (synchronous) { // Fetch status - Task statusTask = Provider.Status(from, false); + Task statusTask = Provider.Status(fromPath, false); statusTask.Wait(); if (statusTask.success) - asset = Provider.CacheStatus(from); + asset = Provider.CacheStatus(fromPath); else asset = null; } @@ -38,11 +34,26 @@ private static Asset GetStatusCachedIfPossible(string from, CachedStatusMode mod return asset; } - private static Asset GetStatusForceUpdate(string from) + static AssetList GetStatusCachedIfPossible(List fromPaths, bool synchronous) { - Task statusTask = Provider.Status(from); - statusTask.Wait(); - return statusTask.assetList.Count > 0 ? statusTask.assetList[0] : null; + var assets = new AssetList {Capacity = fromPaths.Count}; + foreach (var path in fromPaths) + assets.Add(GetStatusCachedIfPossible(path, synchronous)); + return assets; + } + + static Asset GetStatusForceUpdate(string fromPath) + { + var task = Provider.Status(fromPath); + task.Wait(); + return task.assetList.Count > 0 ? task.assetList[0] : null; + } + + static AssetList GetStatusForceUpdate(List fromPaths) + { + var task = Provider.Status(fromPaths.ToArray()); + task.Wait(); + return task.success ? task.assetList : null; } // Handle asset moving @@ -51,7 +62,7 @@ public static AssetMoveResult OnWillMoveAsset(string from, string to) if (!Provider.enabled || EditorUserSettings.WorkOffline) return AssetMoveResult.DidNotMove; - Asset asset = GetStatusCachedIfPossible(from, CachedStatusMode.Sync); + Asset asset = GetStatusCachedIfPossible(from, true); if (asset == null || !asset.IsUnderVersionControl) return AssetMoveResult.DidNotMove; @@ -113,12 +124,9 @@ public static bool IsOpenForEdit(string assetPath, out string message, StatusQue if (string.IsNullOrEmpty(assetPath)) return true; - Asset asset = null; + Asset asset; if (statusOptions == StatusQueryOptions.UseCachedIfPossible || statusOptions == StatusQueryOptions.UseCachedAsync) - { - CachedStatusMode mode = statusOptions == StatusQueryOptions.UseCachedAsync ? CachedStatusMode.Async : CachedStatusMode.Sync; - asset = GetStatusCachedIfPossible(assetPath, mode); - } + asset = GetStatusCachedIfPossible(assetPath, statusOptions == StatusQueryOptions.UseCachedIfPossible); else asset = GetStatusForceUpdate(assetPath); @@ -131,5 +139,34 @@ public static bool IsOpenForEdit(string assetPath, out string message, StatusQue return Provider.IsOpenForEdit(asset); } + + internal static void IsOpenForEdit(List assetPaths, List outNotOpenPaths, StatusQueryOptions statusOptions) + { + if (!Provider.enabled || EditorUserSettings.WorkOffline || assetPaths == null || assetPaths.Count == 0) + return; // everything is editable + + // paths that are empty/null are considered to be editable, so remove them from consideration + assetPaths = assetPaths.Where(p => !string.IsNullOrEmpty(p)).ToList(); + + AssetList assets; + if (statusOptions == StatusQueryOptions.UseCachedIfPossible || statusOptions == StatusQueryOptions.UseCachedAsync) + assets = GetStatusCachedIfPossible(assetPaths, statusOptions == StatusQueryOptions.UseCachedIfPossible); + else + assets = GetStatusForceUpdate(assetPaths); + + if (assets == null) + { + // nothing is editable (we might be disconnected) + outNotOpenPaths.AddRange(assetPaths); + return; + } + + for (var i = 0; i < assetPaths.Count; ++i) + { + var asset = assets[i]; + if (asset == null || !Provider.IsOpenForEdit(asset)) + outNotOpenPaths.Add(assetPaths[i]); + } + } } } diff --git a/Editor/Mono/VersionControl/Common/VCProvider.cs b/Editor/Mono/VersionControl/Common/VCProvider.cs index 550d96ef0c..c6754c414d 100644 --- a/Editor/Mono/VersionControl/Common/VCProvider.cs +++ b/Editor/Mono/VersionControl/Common/VCProvider.cs @@ -184,12 +184,22 @@ static private Task CheckCallbackAndCheckout(AssetList assets, CheckoutMode mode return Internal_Checkout(consolidatedAssetList.ToArray(), mode, changeset); } - static public Task Checkout(AssetList assets, CheckoutMode mode, ChangeSet changeset = null) + static public Task Checkout(AssetList assets, CheckoutMode mode) + { + return Checkout(assets, mode, null); + } + + static public Task Checkout(AssetList assets, CheckoutMode mode, ChangeSet changeset) { return CheckCallbackAndCheckout(assets, mode, changeset); } - static public Task Checkout(string[] assets, CheckoutMode mode, ChangeSet changeset = null) + static public Task Checkout(string[] assets, CheckoutMode mode) + { + return Checkout(assets, mode, null); + } + + static public Task Checkout(string[] assets, CheckoutMode mode, ChangeSet changeset) { var assetList = new AssetList(); foreach (var path in assets) @@ -201,7 +211,12 @@ static public Task Checkout(string[] assets, CheckoutMode mode, ChangeSet change return CheckCallbackAndCheckout(assetList, mode, changeset); } - static public Task Checkout(Object[] assets, CheckoutMode mode, ChangeSet changeset = null) + static public Task Checkout(Object[] assets, CheckoutMode mode) + { + return Checkout(assets, mode, null); + } + + static public Task Checkout(Object[] assets, CheckoutMode mode, ChangeSet changeset) { var assetList = new AssetList(); foreach (var o in assets) @@ -222,7 +237,12 @@ static public bool CheckoutIsValid(Asset asset, CheckoutMode mode) return Internal_CheckoutIsValid(new Asset[] { asset }, mode); } - static public Task Checkout(Asset asset, CheckoutMode mode, ChangeSet changeset = null) + static public Task Checkout(Asset asset, CheckoutMode mode) + { + return Checkout(asset, mode, null); + } + + static public Task Checkout(Asset asset, CheckoutMode mode, ChangeSet changeset) { var assetList = new AssetList(); assetList.Add(asset); @@ -230,7 +250,12 @@ static public Task Checkout(Asset asset, CheckoutMode mode, ChangeSet changeset return CheckCallbackAndCheckout(assetList, mode, changeset); } - static public Task Checkout(string asset, CheckoutMode mode, ChangeSet changeset = null) + static public Task Checkout(string asset, CheckoutMode mode) + { + return Checkout(asset, mode, null); + } + + static public Task Checkout(string asset, CheckoutMode mode, ChangeSet changeset) { var assetList = new AssetList(); assetList.Add(GetAssetByPath(asset)); @@ -238,7 +263,12 @@ static public Task Checkout(string asset, CheckoutMode mode, ChangeSet changeset return CheckCallbackAndCheckout(assetList, mode, changeset); } - static public Task Checkout(UnityEngine.Object asset, CheckoutMode mode, ChangeSet changeset = null) + static public Task Checkout(UnityEngine.Object asset, CheckoutMode mode) + { + return Checkout(asset, mode, null); + } + + static public Task Checkout(UnityEngine.Object asset, CheckoutMode mode, ChangeSet changeset) { var path = AssetDatabase.GetAssetPath(asset); var vcasset = GetAssetByPath(path); @@ -249,7 +279,7 @@ static public Task Checkout(UnityEngine.Object asset, CheckoutMode mode, ChangeS return CheckCallbackAndCheckout(assetList, mode, changeset); } - //*Undocumented + //*Undocumented : intention is to make this public static internal bool PromptAndCheckoutIfNeeded(string[] assets, string promptIfCheckoutIsNeeded, ChangeSet changeset = null) { var assetList = new AssetList(); diff --git a/Editor/Mono/VersionControl/UI/VCWindowPending.cs b/Editor/Mono/VersionControl/UI/VCWindowPending.cs index b2acfeaa17..b59354e450 100644 --- a/Editor/Mono/VersionControl/UI/VCWindowPending.cs +++ b/Editor/Mono/VersionControl/UI/VCWindowPending.cs @@ -2,6 +2,7 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License +using System; using UnityEditor.ShortcutManagement; using UnityEngine; using UnityEditorInternal.VersionControl; @@ -40,6 +41,10 @@ internal class Styles static GUIContent[] sStatusWheel; + DateTime lastRefresh = new DateTime(0); + private int refreshInterval = 1000; // this is in MS + private bool scheduleRefresh = false; + // Workaround to reload vcs info upon domain reload. TODO: Fix VersionControl.ListControl to get rid of this static bool s_DidReload = false; // defaults to false after domain reload @@ -165,19 +170,26 @@ void UpdateWindow() if (!Provider.isActive) { pendingList.Clear(); - Provider.UpdateSettings(); // Try to resend the settings if we by chance has become online again + Provider.UpdateSettings(); // Try to resend the settings if we by chance has become online again Repaint(); return; } - if (Provider.onlineState == OnlineState.Online) + if (TimeElapsed() > refreshInterval) { - Task changesTask = Provider.ChangeSets(); - changesTask.SetCompletionAction(CompletionAction.OnChangeSetsPendingWindow); + if (Provider.onlineState == OnlineState.Online) + { + Task changesTask = Provider.ChangeSets(); + changesTask.SetCompletionAction(CompletionAction.OnChangeSetsPendingWindow); + + Task incomingTask = Provider.Incoming(); + incomingTask.SetCompletionAction(CompletionAction.OnIncomingPendingWindow); + } - Task incomingTask = Provider.Incoming(); - incomingTask.SetCompletionAction(CompletionAction.OnIncomingPendingWindow); + lastRefresh = DateTime.Now; } + else + scheduleRefresh = true; } void OnGotLatest(Task t) @@ -440,13 +452,17 @@ void OnGUI() Color origColor = GUI.color; GUI.color = new Color(1, 1, 1, 1 * .5f); bool refreshButtonClicked = GUILayout.Button(refreshIcon, EditorStyles.toolbarButton); - refresh = refresh || refreshButtonClicked; + refresh = refresh || refreshButtonClicked || scheduleRefresh; GUI.color = origColor; + bool repaint = false; if (refresh) { if (refreshButtonClicked) Provider.InvalidateCache(); + + repaint = true; + scheduleRefresh = false; UpdateWindow(); } @@ -454,8 +470,6 @@ void OnGUI() Rect rect = new Rect(0, toolBarHeight, position.width, position.height - toolBarHeight - k_BottomBarHeight); - bool repaint = false; - GUILayout.EndHorizontal(); // Disabled Window view @@ -642,5 +656,11 @@ void CreateStaticResources() changeIcon.name = "ChangeIcon"; } } + + double TimeElapsed() + { + var elapsed = DateTime.Now - lastRefresh; + return elapsed.TotalMilliseconds; + } } } diff --git a/Editor/Mono/VersionControl/VCAsset.bindings.cs b/Editor/Mono/VersionControl/VCAsset.bindings.cs index c63914edac..77f497f9a6 100644 --- a/Editor/Mono/VersionControl/VCAsset.bindings.cs +++ b/Editor/Mono/VersionControl/VCAsset.bindings.cs @@ -39,7 +39,8 @@ public enum States ReadOnly = 16384, MetaFile = 32768, MovedLocal = 65536, - MovedRemote = 131072 + MovedRemote = 131072, + Unversioned = 262144 } public Asset(string clientPath) diff --git a/Editor/Mono/VersionControl/VCProvider.bindings.cs b/Editor/Mono/VersionControl/VCProvider.bindings.cs index 86aa9dbdd6..636eef5bd5 100644 --- a/Editor/Mono/VersionControl/VCProvider.bindings.cs +++ b/Editor/Mono/VersionControl/VCProvider.bindings.cs @@ -149,6 +149,9 @@ internal static extern CustomCommand[] customCommands [FreeFunction("VersionControlBindings::VCProvider::Internal_PromptAndCheckoutIfNeeded")] private static extern bool Internal_PromptAndCheckoutIfNeeded(string[] assets, string promptIfCheckoutIsNeeded, ChangeSet changeset); + [FreeFunction("VersionControlBindings::VCProvider::MakeEditable")] + static internal extern bool MakeEditable(string[] assets, [Out] string[] editableAssets); + [NativeThrows] [FreeFunction("VersionControlBindings::VCProvider::Internal_Delete")] private static extern Task Internal_Delete(Asset[] assets); diff --git a/Editor/Mono/VisualStudioIntegration/SolutionSynchronizationSettings.cs b/Editor/Mono/VisualStudioIntegration/SolutionSynchronizationSettings.cs index 9277eca08a..38e4c68fc5 100644 --- a/Editor/Mono/VisualStudioIntegration/SolutionSynchronizationSettings.cs +++ b/Editor/Mono/VisualStudioIntegration/SolutionSynchronizationSettings.cs @@ -225,64 +225,4 @@ protected virtual string FrameworksPath() return string.Empty; } } - - static class VSCodeTemplates - { - public static string SettingsJson = @"{ - ""files.exclude"": - { - ""**/.DS_Store"":true, - ""**/.git"":true, - ""**/.gitignore"":true, - ""**/.gitmodules"":true, - ""**/*.booproj"":true, - ""**/*.pidb"":true, - ""**/*.suo"":true, - ""**/*.user"":true, - ""**/*.userprefs"":true, - ""**/*.unityproj"":true, - ""**/*.dll"":true, - ""**/*.exe"":true, - ""**/*.pdf"":true, - ""**/*.mid"":true, - ""**/*.midi"":true, - ""**/*.wav"":true, - ""**/*.gif"":true, - ""**/*.ico"":true, - ""**/*.jpg"":true, - ""**/*.jpeg"":true, - ""**/*.png"":true, - ""**/*.psd"":true, - ""**/*.tga"":true, - ""**/*.tif"":true, - ""**/*.tiff"":true, - ""**/*.3ds"":true, - ""**/*.3DS"":true, - ""**/*.fbx"":true, - ""**/*.FBX"":true, - ""**/*.lxo"":true, - ""**/*.LXO"":true, - ""**/*.ma"":true, - ""**/*.MA"":true, - ""**/*.obj"":true, - ""**/*.OBJ"":true, - ""**/*.asset"":true, - ""**/*.cubemap"":true, - ""**/*.flare"":true, - ""**/*.mat"":true, - ""**/*.meta"":true, - ""**/*.prefab"":true, - ""**/*.unity"":true, - ""build/"":true, - ""Build/"":true, - ""Library/"":true, - ""library/"":true, - ""obj/"":true, - ""Obj/"":true, - ""ProjectSettings/"":true, - ""temp/"":true, - ""Temp/"":true - } -}"; - } } diff --git a/Editor/Mono/VisualStudioIntegration/SolutionSynchronizer.cs b/Editor/Mono/VisualStudioIntegration/SolutionSynchronizer.cs index 442b499a6f..14ccd0bb9a 100644 --- a/Editor/Mono/VisualStudioIntegration/SolutionSynchronizer.cs +++ b/Editor/Mono/VisualStudioIntegration/SolutionSynchronizer.cs @@ -20,6 +20,7 @@ using UnityEditor.Compilation; using UnityEditor.Modules; using UnityEngine; +using UnityEditor.PackageManager; namespace UnityEditor.VisualStudioIntegration { @@ -47,7 +48,7 @@ public string GetAssemblyNameFromScriptPath(string path) public IEnumerable GetAllScriptAssemblies(Func shouldFileBePartOfSolution, string projectDirectory) { - return EditorCompilationInterface.Instance.GetAllScriptAssemblies(EditorScriptCompilationOptions.BuildingForEditor | EditorCompilationInterface.GetAdditionalEditorScriptCompilationOptions()) + return EditorCompilationInterface.Instance.GetAllScriptAssemblies(EditorScriptCompilationOptions.BuildingForEditor | EditorCompilationInterface.GetAdditionalEditorScriptCompilationOptions(), null) .Where(i => 0 < i.Files.Length && i.Files.Any(shouldFileBePartOfSolution)) .Select(x => x.ToMonoIsland(EditorScriptCompilationOptions.BuildingForEditor, string.Empty, projectDirectory)).ToList(); } @@ -88,7 +89,7 @@ enum Mode {"raytrace", ScriptingLanguage.None}, }; - private static readonly string[] reimportSyncExtensions = new[] { ".dll", ".asmdef", ".asmref" }; + private static readonly string[] reimportSyncExtensions = new[] { ".dll", ".asmdef" }; string[] ProjectSupportedExtensions = new string[0]; @@ -109,6 +110,7 @@ enum Mode private readonly ISolutionSynchronizationSettings _settings; private readonly string _projectName; readonly IAssemblyNameProvider m_assemblyNameProvider; + bool m_ShouldGenerateAll; public SolutionSynchronizer(string projectDirectory, ISolutionSynchronizationSettings settings, IAssemblyNameProvider assemblyNameProvider) { @@ -136,7 +138,7 @@ public bool ShouldFileBePartOfSolution(string file) string extension = Path.GetExtension(file); // Exclude files coming from packages except if they are internalized. - if (IsNonInternalizedPackagePath(file)) + if (!m_ShouldGenerateAll && IsNonInternalizedPackagePath(file)) { return false; } @@ -145,17 +147,8 @@ public bool ShouldFileBePartOfSolution(string file) if (extension == ".dll") return true; - // Check if the file is an asmref or asmdef - if (file.Length > 7) - { - var extensionLower = file.Substring(file.Length - 7, 7).ToLower(); - - if (extensionLower.EndsWith(".asmdef")) - return true; - - if (extensionLower.EndsWith(".asmref")) - return true; - } + if (file.ToLower().EndsWith(".asmdef")) + return true; return IsSupportedExtension(extension); } @@ -253,6 +246,7 @@ public void Sync() if (!externalCodeAlreadyGeneratedProjects) { + #pragma warning disable 618 var scriptEditor = ScriptEditorUtility.GetScriptEditorFromPreferences(); GenerateAndWriteSolutionAndProjects(scriptEditor); } @@ -291,27 +285,20 @@ internal void GenerateAndWriteSolutionAndProjects(ScriptEditorUtility.ScriptEdit Profiler.EndSample(); } - if (scriptEditor == ScriptEditorUtility.ScriptEditor.VisualStudioCode) - { - Profiler.BeginSample("WriteVSCodeSettingsFiles"); - WriteVSCodeSettingsFiles(); - Profiler.EndSample(); - } - Profiler.EndSample(); } - IEnumerable ParseResponseFileData(MonoIsland island) + IEnumerable ParseResponseFileData(MonoIsland island) { var systemReferenceDirectories = MonoLibraryHelpers.GetSystemReferenceDirectories(island._api_compatibility_level); - Dictionary responseFilesData = island._responseFiles.ToDictionary(x => x, x => ScriptCompilerBase.ParseResponseFileFromFile( + Dictionary responseFilesData = island._responseFiles.ToDictionary(x => x, x => ScriptCompilerBase.ParseResponseFileFromFile( x, _projectDirectory, systemReferenceDirectories )); - Dictionary responseFilesWithErrors = responseFilesData.Where(x => x.Value.Errors.Any()) + Dictionary responseFilesWithErrors = responseFilesData.Where(x => x.Value.Errors.Any()) .ToDictionary(x => x.Key, x => x.Value); if (responseFilesWithErrors.Any()) @@ -333,7 +320,7 @@ Dictionary GenerateAllAssetProjectParts() foreach (string asset in m_assemblyNameProvider.GetAllAssetPaths()) { // Exclude files coming from packages except if they are internalized. - if (IsNonInternalizedPackagePath(asset)) + if (!m_ShouldGenerateAll && IsNonInternalizedPackagePath(asset)) { continue; } @@ -385,7 +372,7 @@ bool IsNonInternalizedPackagePath(string file) void SyncProject(MonoIsland island, Dictionary allAssetsProjectParts, - IEnumerable responseFilesData, + IEnumerable responseFilesData, List allProjectIslands) { SyncProjectFileIfNotChanged(ProjectFile(island), ProjectText(island, ModeForCurrentExternalEditor(), allAssetsProjectParts, responseFilesData, allProjectIslands)); @@ -480,19 +467,6 @@ private static void SyncFileIfNotChanged(string filename, string newContents) File.WriteAllText(filename, newContents, Encoding.UTF8); } - void WriteVSCodeSettingsFiles() - { - string vsCodeDirectory = Path.Combine(_projectDirectory, ".vscode"); - - if (!Directory.Exists(vsCodeDirectory)) - Directory.CreateDirectory(vsCodeDirectory); - - string vsCodeSettingsJson = Path.Combine(vsCodeDirectory, "settings.json"); - - if (!File.Exists(vsCodeSettingsJson)) - File.WriteAllText(vsCodeSettingsJson, VSCodeTemplates.SettingsJson); - } - public static readonly Regex scriptReferenceExpression = new Regex( @"^Library.ScriptAssemblies.(?(?.*)\.dll$)", RegexOptions.Compiled | RegexOptions.IgnoreCase); @@ -507,14 +481,14 @@ static bool IsAdditionalInternalAssemblyReference(bool isBuildingEditorProject, string ProjectText(MonoIsland island, Mode mode, Dictionary allAssetsProjectParts, - IEnumerable responseFilesData, + IEnumerable responseFilesData, List allProjectIslands) { var projectBuilder = new StringBuilder(ProjectHeader(island, responseFilesData)); var references = new List(); var projectReferences = new List(); Match match; - bool isBuildingEditorProject = island._output.EndsWith("-Editor.dll"); + bool isBuildingEditorProject = island._editor; foreach (string file in island._files) { @@ -639,7 +613,7 @@ internal string SolutionFile() } private string ProjectHeader(MonoIsland island, - IEnumerable responseFilesData) + IEnumerable responseFilesData) { string targetframeworkversion = "v3.5"; string targetLanguageVersion = "4"; @@ -703,11 +677,11 @@ private void SyncSolution(IEnumerable islands) private static Mode ModeForCurrentExternalEditor() { + #pragma warning disable 618 var scriptEditor = ScriptEditorUtility.GetScriptEditorFromPreferences(); if (scriptEditor == ScriptEditorUtility.ScriptEditor.VisualStudio || - scriptEditor == ScriptEditorUtility.ScriptEditor.VisualStudioExpress || - scriptEditor == ScriptEditorUtility.ScriptEditor.VisualStudioCode) + scriptEditor == ScriptEditorUtility.ScriptEditor.VisualStudioExpress) return Mode.UnityScriptAsPrecompiledAssembly; return EditorPrefs.GetBool("kExternalEditorSupportsUnityProj", false) ? Mode.UnityScriptAsUnityProj : Mode.UnityScriptAsPrecompiledAssembly; @@ -801,42 +775,10 @@ public static string GetProjectExtension(ScriptingLanguage language) return ProjectExtensions[language]; } - } - - public static class SolutionGuidGenerator - { - public static string GuidForProject(string projectName) - { - return ComputeGuidHashFor(projectName + "salt"); - } - - public static string GuidForSolution(string projectName, string sourceFileExtension) - { - if (sourceFileExtension.ToLower() == "cs") - // GUID for a C# class library: http://www.codeproject.com/Reference/720512/List-of-Visual-Studio-Project-Type-GUIDs - return "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC"; - - return ComputeGuidHashFor(projectName); - } - - private static string ComputeGuidHashFor(string input) - { - var hash = MD5.Create().ComputeHash(Encoding.Default.GetBytes(input)); - return HashAsGuid(HashToString(hash)); - } - - private static string HashAsGuid(string hash) - { - var guid = hash.Substring(0, 8) + "-" + hash.Substring(8, 4) + "-" + hash.Substring(12, 4) + "-" + hash.Substring(16, 4) + "-" + hash.Substring(20, 12); - return guid.ToUpper(); - } - private static string HashToString(byte[] bs) + public void GenerateAll(bool generateAll) { - var sb = new StringBuilder(); - foreach (byte b in bs) - sb.Append(b.ToString("x2")); - return sb.ToString(); + m_ShouldGenerateAll = generateAll; } } } diff --git a/Editor/Mono/VisualStudioIntegration/UnityVSSupport.cs b/Editor/Mono/VisualStudioIntegration/UnityVSSupport.cs index 9070ff0189..394ea49a36 100644 --- a/Editor/Mono/VisualStudioIntegration/UnityVSSupport.cs +++ b/Editor/Mono/VisualStudioIntegration/UnityVSSupport.cs @@ -8,6 +8,7 @@ using System.Text; using System.Text.RegularExpressions; using Microsoft.Win32; +using Unity.CodeEditor; using UnityEditorInternal; using UnityEngine; using RequiredByNativeCodeAttribute = UnityEngine.Scripting.RequiredByNativeCodeAttribute; @@ -151,7 +152,7 @@ private static void InitializeVisualStudio(string externalEditor) { externalEditor = SyncVS.FindBestVisualStudio(); if (externalEditor != null) - ScriptEditorUtility.SetExternalScriptEditor(externalEditor); + CodeEditor.SetExternalScriptEditor(externalEditor); } VisualStudioVersion vsVersion; diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000000..2303b574a4 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1 @@ +For terms of use, see https://unity3d.com/legal/licenses/Unity_Reference_Only_License diff --git a/Modules/Accessibility/VisionUtility.cs b/Modules/Accessibility/VisionUtility.cs index dcebf5e125..7df416dc0b 100644 --- a/Modules/Accessibility/VisionUtility.cs +++ b/Modules/Accessibility/VisionUtility.cs @@ -6,7 +6,9 @@ using System.Linq; using UnityEngine; using UnityEngine.Scripting; +using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo("Acessibility.VisionUtility.Tests")] namespace UnityEngine.Accessibility { [UsedByNativeCode] @@ -14,30 +16,39 @@ public static class VisionUtility { // http://www.somersault1824.com/wp-content/uploads/2015/02/color-blindness-palette.png // colors are ordered across rows to maximize contrast with small palettes - private static readonly Color[] s_ColorBlindSafePalette = new[] + static readonly Color[] s_ColorBlindSafePalette = new Color[] { - (Color) new Color32(0, 0, 0, 255), - (Color) new Color32(73, 0, 146, 255), -// (Color) new Color32(146, 0, 0, 255), // doesn't look good in editor + new Color32(0, 0, 0, 255), // Not used by profiler because too dark + new Color32(73, 0, 146, 255), // Not used by profiler because too dark +// new Color32(146, 0, 0, 255), // doesn't look good in editor - (Color) new Color32(7, 71, 81, 255), -// (Color) new Color32(0, 109, 219, 255), // tritanopia ambiguous 1 -// (Color) new Color32(146, 73, 0, 255), // doesn't look good in editor + new Color32(7, 71, 81, 255), // Not used by profiler because too dark +// new Color32(0, 109, 219, 255), // tritanopia ambiguous 1 +// new Color32(146, 73, 0, 255), // doesn't look good in editor - (Color) new Color32(0, 146, 146, 255), // tritanopia ambiguous 1 - (Color) new Color32(182, 109, 255, 255), -// (Color) new Color32(219, 109, 0, 255), // tritanopia ambiguous 2; also doesn't look good in editor + new Color32(0, 146, 146, 255), // "Rendering" // tritanopia ambiguous 1 + new Color32(182, 109, 255, 255), // "Scripts", "Managed Jobs", "Burst Jobs" +// new Color32(219, 209, 0, 255), // tritanopia ambiguous 2; also doesn't look good in editor - (Color) new Color32(255, 109, 182, 255), // tritanopia ambiguous 2 - (Color) new Color32(109, 182, 255, 255), - (Color) new Color32(36, 255, 36, 255), + new Color32(255, 109, 182, 255), // "Physics" // tritanopia ambiguous 2 + new Color32(109, 182, 255, 255), // "Animnation" + new Color32(36, 255, 36, 255), // "GC" - (Color) new Color32(255, 182, 219, 255), - (Color) new Color32(182, 219, 255, 255), - (Color) new Color32(255, 255, 109, 255), + new Color32(255, 182, 219, 255), // "VSync" + new Color32(182, 219, 255, 255), // "GI" + new Color32(255, 255, 109, 255), // UI: "UI Layout", "UI Render" + // Bugfix additions to address https://fogbugz.unity3d.com/f/cases/1101387/ + new Color32(30, 92, 92, 255), // Profiler - CPU Usage Chart: "Other" category + new Color32(74, 154, 87, 255), // Profiler - GI Chart: "Blocked Command Write" - CPU Timeline: "Audio" + new Color32(113, 66, 183, 255), // CPU Timeline: "Audio Job" + new Color32(162, 66, 183, 255), // CPU Timeline: "Audio Update Job" + new Color32(178, 92, 25, 255), // CPU Timeline: "Memory Allocation" + new Color32(100, 100, 100, 255), // CPU Timeline: "Internal" + new Color32(80, 203, 181, 255), // CPU Timeline: "Build Interface" + new Color32(82, 205, 242, 255), // CPU Timeline: "Input" }; - private static readonly float[] s_ColorBlindSafePaletteLuminanceValues = + static readonly float[] s_ColorBlindSafePaletteLuminanceValues = s_ColorBlindSafePalette.Select(c => ComputePerceivedLuminance(c)).ToArray(); // https://en.wikipedia.org/wiki/Relative_luminance @@ -47,27 +58,75 @@ internal static float ComputePerceivedLuminance(Color color) return Mathf.LinearToGammaSpace(0.2126f * color.r + 0.7152f * color.g + 0.0722f * color.b); } + internal static void GetLuminanceValuesForPalette(Color[] palette, ref float[] outLuminanceValues) + { + Debug.Assert(palette != null && outLuminanceValues != null, "Passed in arrays can't be null."); + Debug.Assert(palette.Length == outLuminanceValues.Length, "Passed in arrays need to be of the same length."); + for (int i = 0; i < palette.Length; i++) + { + outLuminanceValues[i] = ComputePerceivedLuminance(palette[i]); + } + } + public static int GetColorBlindSafePalette(Color[] palette, float minimumLuminance, float maximumLuminance) + { + if (palette == null) + throw new ArgumentNullException("palette"); + unsafe + { + fixed(Color * p = palette) + { + return GetColorBlindSafePaletteInternal(p, palette.Length, minimumLuminance, maximumLuminance, useColor32: false); + } + } + } + + internal static int GetColorBlindSafePalette(Color32[] palette, float minimumLuminance, float maximumLuminance) + { + if (palette == null) + throw new ArgumentNullException("palette"); + unsafe + { + fixed(Color32 * p = palette) + { + return GetColorBlindSafePaletteInternal(p, palette.Length, minimumLuminance, maximumLuminance, useColor32: true); + } + } + } + + // MethodImplOptions.AggressiveInlining = 256 + [MethodImpl(256)] + unsafe static int GetColorBlindSafePaletteInternal(void* palette, int paletteLength, float minimumLuminance, float maximumLuminance, bool useColor32) { if (palette == null) throw new ArgumentNullException("palette"); - Color[] acceptableColors = Enumerable.Range(0, s_ColorBlindSafePalette.Length).Where( + var acceptableColors = Enumerable.Range(0, s_ColorBlindSafePalette.Length).Where( i => s_ColorBlindSafePaletteLuminanceValues[i] >= minimumLuminance && s_ColorBlindSafePaletteLuminanceValues[i] <= maximumLuminance ).Select(i => s_ColorBlindSafePalette[i] ).ToArray(); - int numUniqueColors = Mathf.Min(palette.Length, acceptableColors.Length); + int numUniqueColors = Mathf.Min(paletteLength, acceptableColors.Length); if (numUniqueColors > 0) { - for (int i = 0, count = palette.Length; i < count; ++i) - palette[i] = acceptableColors[i % numUniqueColors]; + for (int i = 0, count = paletteLength; i < count; ++i) + { + if (useColor32) + ((Color32*)palette)[i] = (Color32)acceptableColors[i % numUniqueColors]; + else + ((Color*)palette)[i] = (Color)acceptableColors[i % numUniqueColors]; + } } else { - for (int i = 0, count = palette.Length; i < count; ++i) - palette[i] = default(Color); + for (int i = 0, count = paletteLength; i < count; ++i) + { + if (useColor32) + ((Color32*)palette)[i] = default(Color32); + else + ((Color*)palette)[i] = default(Color); + } } return numUniqueColors; diff --git a/Modules/AndroidJNI/AndroidJava.cs b/Modules/AndroidJNI/AndroidJava.cs index eb181574ff..714ec33815 100644 --- a/Modules/AndroidJNI/AndroidJava.cs +++ b/Modules/AndroidJNI/AndroidJava.cs @@ -832,13 +832,28 @@ private static IntPtr GetStaticMethodID(string clazz, string methodName, string } } + private static IntPtr GetMethodID(string clazz, string methodName, string signature) + { + IntPtr jclass = AndroidJNISafe.FindClass(clazz); + try + { + return AndroidJNISafe.GetMethodID(jclass, methodName, signature); + } + finally + { + AndroidJNISafe.DeleteLocalRef(jclass); + } + } + private const string RELECTION_HELPER_CLASS_NAME = "com/unity3d/player/ReflectionHelper"; private static readonly GlobalJavaObjectRef s_ReflectionHelperClass = new GlobalJavaObjectRef(AndroidJNISafe.FindClass(RELECTION_HELPER_CLASS_NAME)); private static readonly IntPtr s_ReflectionHelperGetConstructorID = GetStaticMethodID(RELECTION_HELPER_CLASS_NAME, "getConstructorID", "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/reflect/Constructor;"); private static readonly IntPtr s_ReflectionHelperGetMethodID = GetStaticMethodID(RELECTION_HELPER_CLASS_NAME, "getMethodID", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Z)Ljava/lang/reflect/Method;"); private static readonly IntPtr s_ReflectionHelperGetFieldID = GetStaticMethodID(RELECTION_HELPER_CLASS_NAME, "getFieldID", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Z)Ljava/lang/reflect/Field;"); + private static readonly IntPtr s_ReflectionHelperGetFieldSignature = GetStaticMethodID(RELECTION_HELPER_CLASS_NAME, "getFieldSignature", "(Ljava/lang/reflect/Field;)Ljava/lang/String;"); private static readonly IntPtr s_ReflectionHelperNewProxyInstance = GetStaticMethodID(RELECTION_HELPER_CLASS_NAME, "newProxyInstance", "(JLjava/lang/Class;)Ljava/lang/Object;"); private static readonly IntPtr s_ReflectionHelperSetNativeExceptionOnProxy = GetStaticMethodID(RELECTION_HELPER_CLASS_NAME, "setNativeExceptionOnProxy", "(Ljava/lang/Object;JZ)V"); + private static readonly IntPtr s_FieldGetDeclaringClass = GetMethodID("java/lang/reflect/Field", "getDeclaringClass", "()Ljava/lang/Class;"); public static IntPtr GetConstructorMember(IntPtr jclass, string signature) { @@ -891,6 +906,18 @@ public static IntPtr GetFieldMember(IntPtr jclass, string fieldName, string sign } } + public static IntPtr GetFieldClass(IntPtr field) + { + return AndroidJNISafe.CallObjectMethod(field, s_FieldGetDeclaringClass, null); + } + + public static string GetFieldSignature(IntPtr field) + { + jvalue[] jniArgs = new jvalue[1]; + jniArgs[0].l = field; + return AndroidJNISafe.CallStaticStringMethod(s_ReflectionHelperClass, s_ReflectionHelperGetFieldSignature, jniArgs); + } + public static IntPtr NewProxyInstance(IntPtr delegateHandle, IntPtr interfaze) { jvalue[] jniArgs = new jvalue[2]; @@ -1395,24 +1422,37 @@ private static IntPtr GetMethodIDFallback(IntPtr jclass, string methodName, stri public static IntPtr GetFieldID(IntPtr jclass, string fieldName, string signature, bool isStatic) { - IntPtr field = IntPtr.Zero; + IntPtr memberID = IntPtr.Zero; + Exception reflectEx = null; + AndroidJNI.PushLocalFrame(10); try { - field = AndroidReflection.GetFieldMember(jclass, fieldName, signature, isStatic); - return AndroidJNISafe.FromReflectedField(field); + IntPtr field = AndroidReflection.GetFieldMember(jclass, fieldName, signature, isStatic); + if (!isStatic) + jclass = AndroidReflection.GetFieldClass(field); + signature = AndroidReflection.GetFieldSignature(field); } catch (Exception e) { - IntPtr memberID = isStatic + reflectEx = e; + } + + try + { + memberID = isStatic ? AndroidJNISafe.GetStaticFieldID(jclass, fieldName, signature) : AndroidJNISafe.GetFieldID(jclass, fieldName, signature); - if (memberID != IntPtr.Zero) - return memberID; - throw e; + if (memberID == IntPtr.Zero) + { + if (reflectEx != null) + throw reflectEx; + throw new Exception(string.Format("Field {0} or type signature {1} not found", fieldName, signature)); + } + return memberID; } finally { - AndroidJNISafe.DeleteLocalRef(field); + AndroidJNI.PopLocalFrame(IntPtr.Zero); } } diff --git a/Modules/Animation/ScriptBindings/AnimationClip.bindings.cs b/Modules/Animation/ScriptBindings/AnimationClip.bindings.cs index 08a9f68d5f..e0dc4483f2 100644 --- a/Modules/Animation/ScriptBindings/AnimationClip.bindings.cs +++ b/Modules/Animation/ScriptBindings/AnimationClip.bindings.cs @@ -49,7 +49,7 @@ public void SampleAnimation(GameObject go, float time) public extern float frameRate { get; set; } [FreeFunction("AnimationClipBindings::Internal_SetCurve", HasExplicitThis = true)] - public extern void SetCurve([NotNull] string relativePath, Type type, [NotNull] string propertyName, AnimationCurve curve); + public extern void SetCurve([NotNull] string relativePath, [NotNull] Type type, [NotNull] string propertyName, AnimationCurve curve); //*undocumented* public extern void EnsureQuaternionContinuity(); diff --git a/Modules/AssetPipelineEditor/AssetPostprocessors/ModelImporterPostProcessor.cs b/Modules/AssetPipelineEditor/AssetPostprocessors/ModelImporterPostProcessor.cs index d9d0f2f95b..13f1384da6 100644 --- a/Modules/AssetPipelineEditor/AssetPostprocessors/ModelImporterPostProcessor.cs +++ b/Modules/AssetPipelineEditor/AssetPostprocessors/ModelImporterPostProcessor.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using UnityEditorInternal; using UnityEngine; using Object = UnityEngine.Object; @@ -12,9 +13,12 @@ namespace UnityEditor { internal class ModelImporterPostProcessor : AssetPostprocessor { + static bool AskedForBumpMap = false; + static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromPath) { List loadedAssets = new List(); + bool oneFound = false; try { foreach (var assetPath in importedAssets) @@ -32,6 +36,7 @@ static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAsse var embeddedMaterials = AssetDatabase.LoadAllAssetsAtPath(assetPath).OfType(); foreach (var material in embeddedMaterials) { + oneFound = true; BumpMapSettings.PerformBumpMapCheck(material); } } @@ -39,11 +44,25 @@ static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAsse } finally { + if (oneFound && !AskedForBumpMap) + { + AskedForBumpMap = true; + // We cannot open the BumpMapTexturesWindow here because the Editor Layout may not have been loaded yet + // and will destroy the window when doing so. So lets wait for the first frame to open it. + EditorApplication.update += OpenBumpMapCheckWindow; + } foreach (var o in loadedAssets) { Resources.UnloadAsset(o); } } } + + static void OpenBumpMapCheckWindow() + { + AskedForBumpMap = false; + EditorApplication.update -= OpenBumpMapCheckWindow; + InternalEditorUtility.PerformUnmarkedBumpMapTexturesFixing(); + } } } diff --git a/Modules/AssetPipelineEditor/ImportSettings/AssetImporterEditor.bindings.cs b/Modules/AssetPipelineEditor/ImportSettings/AssetImporterEditor.bindings.cs index 93e07fec99..807e5964ae 100644 --- a/Modules/AssetPipelineEditor/ImportSettings/AssetImporterEditor.bindings.cs +++ b/Modules/AssetPipelineEditor/ImportSettings/AssetImporterEditor.bindings.cs @@ -17,6 +17,8 @@ public abstract partial class AssetImporterEditor [FreeFunction] private static extern bool ReleaseInspectorCopy(int instanceID); [FreeFunction] + private static extern void FixCacheCount(int instanceID, int count); + [FreeFunction] private static extern int GetInspectorCopyCount(int instanceID); [FreeFunction("IsMetaDataSerializationEqual")] private static extern bool IsSerializedDataEqual([NotNull] Object source); diff --git a/Modules/AssetPipelineEditor/ImportSettings/AssetImporterEditor.cs b/Modules/AssetPipelineEditor/ImportSettings/AssetImporterEditor.cs index faf5c0622c..f895f30be3 100644 --- a/Modules/AssetPipelineEditor/ImportSettings/AssetImporterEditor.cs +++ b/Modules/AssetPipelineEditor/ImportSettings/AssetImporterEditor.cs @@ -5,15 +5,114 @@ using System; using System.Collections.Generic; using System.Linq; -using System.IO; using UnityEngine; -using UnityEngine.Experimental.AssetBundlePatching; using Object = UnityEngine.Object; namespace UnityEditor.Experimental.AssetImporters { public abstract partial class AssetImporterEditor : Editor { + /// + /// This class allows us to save the dirty state of the current editor targets. + /// We save it on each ApplyModifiedProperties (at the end of the Inspector GUI loop) + /// If the dirty count changed during the Update (at the beginning of the Inspector GUI loop) + /// That means the target has been updated outside of the editor (by calling Reset, applying a Preset or performing any static menu action) + /// And thus we need to re-initialize the extra instances before updating the serializedObject. + /// + protected sealed class ExtraDataSerializedObject : SerializedObject + { + List m_TargetDirtyCount; + AssetImporterEditor m_Editor; + + private ExtraDataSerializedObject(Object obj) + : base(obj) {} + + private ExtraDataSerializedObject(Object obj, Object context) + : base(obj, context) {} + + private ExtraDataSerializedObject(Object[] objs) + : base(objs) {} + + private ExtraDataSerializedObject(Object[] objs, Object context) + : base(objs, context) {} + + internal ExtraDataSerializedObject(Object[] objs, AssetImporterEditor editor) + : base(objs) + { + m_Editor = editor; + } + + void UpdateTargetDirtyCount() + { + if (m_Editor != null) + { + // When coming back from a target reload + // this is the very first place we can catch mismatching saved data and fix them. + if (m_Editor.m_TargetsReloaded) + { + SaveTargetDirtyCount(); + m_Editor.m_TargetsReloaded = false; + for (int i = 0; i < m_Editor.targets.Length; i++) + UpdateSavedData(m_Editor.targets[i]); + return; + } + + if (m_TargetDirtyCount != null) + { + for (int i = 0; i < m_Editor.targets.Length; i++) + { + var newCount = EditorUtility.GetDirtyCount(m_Editor.targets[i]); + if (m_TargetDirtyCount[i] != newCount) + { + m_TargetDirtyCount[i] = newCount; + m_Editor.InitializeExtraDataInstance(targetObjects[i], i); + } + } + } + } + } + + void SaveTargetDirtyCount() + { + if (m_Editor != null) + { + if (m_TargetDirtyCount == null) + { + m_TargetDirtyCount = new int[m_Editor.targets.Length].ToList(); + } + + for (int i = 0; i < m_Editor.targets.Length; i++) + { + m_TargetDirtyCount[i] = EditorUtility.GetDirtyCount(m_Editor.targets[i]); + } + } + } + + public new void Update() + { + UpdateTargetDirtyCount(); + base.Update(); + } + + public new void UpdateIfRequiredOrScript() + { + UpdateTargetDirtyCount(); + base.UpdateIfRequiredOrScript(); + } + + public new void ApplyModifiedProperties() + { + SaveTargetDirtyCount(); + base.ApplyModifiedProperties(); + } + + public new void SetIsDifferentCacheDirty() + { + SaveTargetDirtyCount(); + base.SetIsDifferentCacheDirty(); + } + } + static class Styles { public static string localizedTitleString = L10n.Tr("{0} Import Settings"); @@ -39,16 +138,30 @@ static class Styles // if they want to modify data outside the Importer serialization in the ImporterInspector. // This allow support for multiple inspectors, multiple selections and assembly reload. // See an example usage in AssemblyDefinitionImporterInspector. - protected Object[] extraDataTargets { get; private set; } - protected Object extraDataTarget => extraDataTargets[referenceTargetIndex]; - SerializedObject m_ExtraDataSerializedObject; - protected SerializedObject extraDataSerializedObject + Object[] m_ExtraDataTargets; + protected Object[] extraDataTargets + { + get + { + if (!m_AllowMultiObjectAccess) + Debug.LogError("The targets array should not be used inside OnSceneGUI or OnPreviewGUI. Use the single target property instead."); + return m_ExtraDataTargets; + } + } + + protected Object extraDataTarget => m_ExtraDataTargets[referenceTargetIndex]; + + ExtraDataSerializedObject m_ExtraDataSerializedObject; + protected ExtraDataSerializedObject extraDataSerializedObject { get { - if (m_ExtraDataSerializedObject == null && extraDataType != null) + if (extraDataType != null) { - m_ExtraDataSerializedObject = new SerializedObject(extraDataTargets); + if (m_ExtraDataSerializedObject == null) + { + m_ExtraDataSerializedObject = new ExtraDataSerializedObject(m_ExtraDataTargets, this); + } } return m_ExtraDataSerializedObject; } @@ -63,6 +176,7 @@ protected SerializedObject extraDataSerializedObject // we need to keep a list of unreleased instances in case the user cancel the de-selection // we are using these instances to keep the same apply/revert status with the forced re-selection static List s_UnreleasedInstances; + List m_TargetsInstanceID; // Check to make sure Users implemented their Inspector correctly for the Cancel deselection mechanism. bool m_ApplyRevertGUICalled; // Adding a check on OnEnable to make sure users call the base class, as it used to do nothing. @@ -75,6 +189,7 @@ protected SerializedObject extraDataSerializedObject // If the Inspector is not null and not Locked, then change Selection.Object list back. InspectorWindow m_Inspector; bool m_HasInspectorBeenSeenLocked = false; + bool m_TargetsReloaded = false; // Called from ActiveEditorTracker.cpp to setup the target editor once created before Awake and OnEnable of the Editor. internal void InternalSetAssetImporterTargetEditor(Object editor) @@ -83,83 +198,91 @@ internal void InternalSetAssetImporterTargetEditor(Object editor) m_InstantApply = m_AssetEditor == null || m_AssetEditor.target == null; } - // Called from a various number of places, like after an assembly reload or when the Editor gets created. - internal sealed override void InternalSetTargets(Object[] t) + void CheckExtraDataArray() { - base.InternalSetTargets(t); - if (extraDataType != null) { if (!typeof(ScriptableObject).IsAssignableFrom(extraDataType)) { - Debug.LogError("Custom Data objects needs to be ScriptableObject to support assembly reloads and Undo/Redo"); - extraDataTargets = null; + Debug.LogError("Extra Data objects needs to be ScriptableObject to support assembly reloads and Undo/Redo"); + m_ExtraDataTargets = null; } else { - extraDataTargets = new Object[t.Length]; + var tempObject = ScriptableObject.CreateInstance(extraDataType); + if (MonoScript.FromScriptableObject(tempObject) == null) + { + Debug.LogWarning($"Unable to find a MonoScript for {extraDataType.FullName}. The inspector may not reload properly after an assembly reload. Check that the definition is in a file of the same name."); + } + DestroyImmediate(tempObject); + m_ExtraDataTargets = new Object[targets.Length]; } } else { - extraDataTargets = null; + m_ExtraDataTargets = null; } + } + + // Called from a various number of places, like after an assembly reload or when the Editor gets created. + internal sealed override void InternalSetTargets(Object[] t) + { + base.InternalSetTargets(t); if (m_CopySaved) // coming back from an assembly reload or asset re-import { - if (extraDataTargets != null) // we need to recreate the user custom array + if (extraDataType != null && m_ExtraDataTargets != null) // we need to recreate the user custom array { // just get back the data from customSerializedData array, it gets serialized and reconstructed properly - extraDataSerializedObject.SetIsDifferentCacheDirty(); - extraDataTargets = extraDataSerializedObject.targetObjects; - } - foreach (var index in AssetWasUpdated()) - { - ResetHash(index); - ReloadAssetData(index); + m_ExtraDataTargets = extraDataSerializedObject.targetObjects; } + ReloadTargets(AssetWasUpdated()); } else // newly created editor { + CheckExtraDataArray(); var loadedIds = new List(t.Length); for (int i = 0; i < t.Length; ++i) { int instanceID = t[i].GetInstanceID(); loadedIds.Add(instanceID); var extraData = CreateOrReloadInspectorCopy(instanceID); - if (extraDataTargets != null) + if (m_ExtraDataTargets != null) { // we got the data from another instance if (extraData != null) - extraDataTargets[i] = extraData; + m_ExtraDataTargets[i] = extraData; else { - extraDataTargets[i] = ScriptableObject.CreateInstance(extraDataType); - InitializeExtraDataInstance(extraDataTargets[i], i); - SaveUserData(instanceID, extraDataTargets[i]); + m_ExtraDataTargets[i] = ScriptableObject.CreateInstance(extraDataType); + m_ExtraDataTargets[i].hideFlags = HideFlags.DontUnloadUnusedAsset | HideFlags.DontSaveInEditor; + InitializeExtraDataInstance(m_ExtraDataTargets[i], i); + SaveUserData(instanceID, m_ExtraDataTargets[i]); } } // proceed to an editor count check to make sure we have the proper number of instances saved. // If it is not the case, then a dispose was not done properly. - var editors = Resources.FindObjectsOfTypeAll(); + var editors = Resources.FindObjectsOfTypeAll(this.GetType()).Cast(); int count = editors.Count(e => e.targets.Contains(t[i])); - if (s_UnreleasedInstances != null && s_UnreleasedInstances.Contains(instanceID)) - count++; + if (s_UnreleasedInstances != null) + { + count += s_UnreleasedInstances.Count(id => id == instanceID); + } var instances = GetInspectorCopyCount(instanceID); if (count != instances) { - // Preemptively dispose the extra instance of the object so we fall back in a correct state. - if (count == instances - 1) - ReleaseInspectorCopy(instanceID); if (!CanEditorSurviveAssemblyReload()) { - Debug.LogError($"The previous instance of {GetType()} has not been disposed correctly. Make sure {GetType()} is a valid MonoScript."); + Debug.LogError($"The previous instance of {GetType()} was not un-loaded properly. The script has to be declared in a file with the same name."); } else { Debug.LogError($"The previous instance of {GetType()} has not been disposed correctly. Make sure you are calling base.OnDisable() in your AssetImporterEditor implementation."); } + + // Fix the cache count so it does not fail anymore. + FixCacheCount(instanceID, count); } } @@ -177,6 +300,7 @@ internal sealed override void InternalSetTargets(Object[] t) } } + m_TargetsInstanceID = loadedIds; m_CopySaved = true; } } @@ -198,8 +322,8 @@ void FixImporterAssetbundleName(string arg1, string arg2) { for (int i = 0; i < targets.Length; i++) { - var importer = (AssetImporter)targets[i]; - if (importer.assetPath == arg1) + var importer = targets[i] as AssetImporter; + if (importer != null && importer.assetPath == arg1) { FixSavedAssetbundleSettings(importer.GetInstanceID(), new PropertyModification[] { @@ -227,7 +351,7 @@ void FixImporterAssetbundleName(string arg1, string arg2) protected virtual Type extraDataType => null; protected virtual void InitializeExtraDataInstance(Object extraData, int targetIndex) { - // Will never be called until CustomDataType is not null. + throw new NotImplementedException("InitializeExtraDataInstance must be implemented when extraDataType is overridden."); } // prevent application quit if user cancel the setting changes apply/revert @@ -338,22 +462,16 @@ public virtual void OnDisable() { s_UnreleasedInstances = new List(); } - foreach (var t in targets) + foreach (var t in m_TargetsInstanceID) { - if (t != null) - { - s_UnreleasedInstances.Add(t.GetInstanceID()); - } + s_UnreleasedInstances.Add(t); } } else { - foreach (var t in targets) + foreach (var t in m_TargetsInstanceID) { - if (t != null) - { - ReleaseInspectorCopy(t.GetInstanceID()); - } + ReleaseInspectorCopy(t); } } } @@ -427,7 +545,6 @@ bool CheckForApplyOnClose(bool isQuitting = false) case 0: Apply(); // we need to call Apply before re-importing in case the user overriden it. ImportAssets(assetPaths.ToArray()); - ResetValues(); break; case 1: return false; @@ -452,35 +569,26 @@ public override void OnInspectorGUI() ApplyRevertGUI(); } - private string[] GetAssetPaths() + IEnumerable GetAssetPaths() { - Object[] allTargets = targets; - string[] paths = new string[allTargets.Length]; - for (int i = 0; i < allTargets.Length; i++) - { - AssetImporter importer = allTargets[i] as AssetImporter; - paths[i] = importer.assetPath; - } - return paths; + return targets.OfType().Select(i => i.assetPath); } private void ReloadAssetData(int index) { - serializedObject.SetIsDifferentCacheDirty(); if (extraDataSerializedObject != null) { extraDataSerializedObject.SetIsDifferentCacheDirty(); - InitializeExtraDataInstance(extraDataTargets[index], index); + InitializeExtraDataInstance(m_ExtraDataTargets[index], index); extraDataSerializedObject.Update(); } UpdateSavedData(targets[index]); - serializedObject.Update(); } protected virtual void ResetValues() { - serializedObject.ApplyModifiedProperties(); - extraDataSerializedObject?.ApplyModifiedProperties(); + serializedObject.SetIsDifferentCacheDirty(); + extraDataSerializedObject?.SetIsDifferentCacheDirty(); for (int i = 0; i < targets.Length; ++i) RevertObject(targets[i]); extraDataSerializedObject?.Update(); @@ -505,7 +613,7 @@ protected virtual void Apply() UpdateSavedData(targets[i]); } - private IEnumerable AssetWasUpdated() + IEnumerable AssetWasUpdated() { for (int i = 0; i < targets.Length; i++) { @@ -534,26 +642,20 @@ protected internal void ApplyAndImport() { Apply(); ImportAssets(GetAssetPaths()); - ResetValues(); } - private void ImportAssets(string[] paths) + static void ImportAssets(IEnumerable paths) { // When using the cache server we have to write all import settings to disk first. // Then perform the import (Otherwise the cache server will not be used for the import) - foreach (string path in paths) - AssetDatabase.WriteImportSettingsIfDirty(path); - - try + foreach (var path in paths) { - AssetDatabase.StartAssetEditing(); - foreach (string path in paths) - AssetDatabase.ImportAsset(path); - } - finally - { - AssetDatabase.StopAssetEditing(); + AssetDatabase.WriteImportSettingsIfDirty(path); } + AssetDatabase.StartAssetEditing(); + foreach (string path in paths) + AssetDatabase.ImportAsset(path); + AssetDatabase.StopAssetEditing(); } protected void RevertButton() @@ -599,8 +701,17 @@ protected void ApplyRevertGUI() serializedObject.Update(); } + if (extraDataSerializedObject != null && extraDataSerializedObject.hasModifiedProperties) + { + Debug.LogWarning("OnInspectorGUI should call extraDataSerializedObject.Update() at its beginning and extraDataSerializedObject.ApplyModifiedProperties() before calling ApplyRevertGUI() method."); + extraDataSerializedObject.ApplyModifiedProperties(); + extraDataSerializedObject.Update(); + } + if (!needsApplyRevert) { + if (extraDataSerializedObject != null && HasModified()) + Apply(); // user may have extra data that needs to be applied back to the target. return; } @@ -622,16 +733,8 @@ protected void ApplyRevertGUI() var updatedAssets = AssetWasUpdated(); if (updatedAssets.Any() && Event.current.type != EventType.Layout) { - IPreviewable previewable = preview; - if (previewable != null) - previewable.ReloadPreviewInstances(); - - foreach (var index in updatedAssets) - { - ResetHash(index); - ReloadAssetData(index); - } - applied = true; + ReloadTargets(updatedAssets); + applied = false; } // asset has changed... @@ -640,6 +743,25 @@ protected void ApplyRevertGUI() Repaint(); } } + + void ReloadTargets(IEnumerable targetIndices) + { + if (targetIndices.Any()) + { + if (preview != null) + { + ReloadPreviewInstances(); + Repaint(); + } + + foreach (var index in targetIndices) + { + ResetHash(index); + ReloadAssetData(index); + } + m_TargetsReloaded = true; + } + } } internal class AssetImporterEditorPostProcessAsset : AssetPostprocessor diff --git a/Modules/AssetPipelineEditor/ImportSettings/AudioImporterInspector.cs b/Modules/AssetPipelineEditor/ImportSettings/AudioImporterInspector.cs index 3820c68b33..a7bfb948e5 100644 --- a/Modules/AssetPipelineEditor/ImportSettings/AudioImporterInspector.cs +++ b/Modules/AssetPipelineEditor/ImportSettings/AudioImporterInspector.cs @@ -3,14 +3,13 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using UnityEngine; -using UnityEditor; using UnityEditor.Build; - using System.Collections.Generic; using System; using System.Linq; using UnityEditor.Experimental.AssetImporters; using System.Globalization; +using Object = UnityEngine.Object; namespace UnityEditor { @@ -18,55 +17,18 @@ namespace UnityEditor [CanEditMultipleObjects] internal class AudioImporterInspector : AssetImporterEditor { - private static class Styles - { - public static readonly string[] kSampleRateStrings = new[] {"8,000 Hz", "11,025 Hz", "22,050 Hz", "44,100 Hz", "48,000 Hz", "96,000 Hz", "192,000 Hz"}; - public static readonly int[] kSampleRateValues = new[] {8000, 11025, 22050, 44100, 48000, 96000, 192000}; - } - - private struct MultiValueStatus - { - public bool multiLoadType; - public bool multiSampleRateSetting; - public bool multiSampleRateOverride; - public bool multiCompressionFormat; - public bool multiQuality; - public bool multiConversionMode; - } - - private struct SampleSettingProperties + static class Style { - public AudioImporterSampleSettings settings; - - //Override the settings for all the targets (only used for the platform overrides) - public bool forcedOverrideState; - public bool overrideIsForced; - - //Overridden status - public bool loadTypeChanged; - public bool sampleRateSettingChanged; - public bool sampleRateOverrideChanged; - public bool compressionFormatChanged; - public bool qualityChanged; - public bool conversionModeChanged; - - public bool HasModified() - { - return overrideIsForced || loadTypeChanged || sampleRateSettingChanged || sampleRateOverrideChanged || - compressionFormatChanged || qualityChanged || conversionModeChanged; - } - - public void ClearChangedFlags() - { - forcedOverrideState = false; - overrideIsForced = false; - loadTypeChanged = false; - sampleRateSettingChanged = false; - sampleRateOverrideChanged = false; - compressionFormatChanged = false; - qualityChanged = false; - conversionModeChanged = false; - } + public static readonly GUIContent[] kSampleRateStrings = new[] {"8,000 Hz", "11,025 Hz", "22,050 Hz", "44,100 Hz", "48,000 Hz", "96,000 Hz", "192,000 Hz"}.Select(s => new GUIContent(s)).ToArray(); + public static readonly int[] kSampleRateValues = {8000, 11025, 22050, 44100, 48000, 96000, 192000}; + + public static GUIContent LoadType = EditorGUIUtility.TrTextContent("Load Type"); + public static GUIContent PreloadAudioData = EditorGUIUtility.TrTextContent("Preload Audio Data"); + public static GUIContent CompressionFormat = EditorGUIUtility.TrTextContent("Compression Format"); + public static GUIContent Quality = EditorGUIUtility.TrTextContent("Quality"); + public static GUIContent SampleRateSetting = EditorGUIUtility.TrTextContent("Sample Rate Setting"); + public static GUIContent SampleRate = EditorGUIUtility.TrTextContent("Sample Rate"); + public static GUIContent DefaultPlatform = EditorGUIUtility.TrTextContent("Default"); } public SerializedProperty m_ForceToMono; @@ -76,151 +38,76 @@ public void ClearChangedFlags() public SerializedProperty m_LoadInBackground; public SerializedProperty m_OrigSize; public SerializedProperty m_CompSize; + public SerializedProperty m_DefaultSampleSettings; - private SampleSettingProperties m_DefaultSampleSettings; - private Dictionary m_SampleSettingOverrides; + bool m_SelectionContainsTrackerFile; - private IEnumerable GetAllAudioImporterTargets() + [Serializable] + class AudioImporterPlatformSettings { - foreach (UnityEngine.Object importer in targets) - { - AudioImporter audioImporter = importer as AudioImporter; - if (audioImporter != null) - yield return audioImporter; - } + public BuildTargetGroup platform; + public bool isOverridden; + public AudioImporterSampleSettings settings; } - private bool SyncSettingsToBackend() + class PlatformSettings : ScriptableObject { - BuildPlatform[] validPlatforms = BuildPlatforms.instance.GetValidPlatforms().ToArray(); - - foreach (AudioImporter importer in GetAllAudioImporterTargets()) - { - { - AudioImporterSampleSettings importerDefaults = importer.defaultSampleSettings; - - //Importer default settings - if (m_DefaultSampleSettings.loadTypeChanged) - importerDefaults.loadType = m_DefaultSampleSettings.settings.loadType; - - if (m_DefaultSampleSettings.sampleRateSettingChanged) - importerDefaults.sampleRateSetting = m_DefaultSampleSettings.settings.sampleRateSetting; - - if (m_DefaultSampleSettings.sampleRateOverrideChanged) - importerDefaults.sampleRateOverride = m_DefaultSampleSettings.settings.sampleRateOverride; - - if (m_DefaultSampleSettings.compressionFormatChanged) - importerDefaults.compressionFormat = m_DefaultSampleSettings.settings.compressionFormat; - - if (m_DefaultSampleSettings.qualityChanged) - importerDefaults.quality = m_DefaultSampleSettings.settings.quality; + public List sampleSettingOverrides; + } - if (m_DefaultSampleSettings.conversionModeChanged) - importerDefaults.conversionMode = m_DefaultSampleSettings.settings.conversionMode; + protected override Type extraDataType => typeof(PlatformSettings); - //Set the default settings on the importer after the changes. - importer.defaultSampleSettings = importerDefaults; - } - - //Get all the valid platforms, and write changes only for those ones + protected override void InitializeExtraDataInstance(Object extraData, int targetIndex) + { + var settings = extraData as PlatformSettings; + var audioImporter = targets[targetIndex] as AudioImporter; + if (settings != null && audioImporter != null) + { + // We need to sort them so every extraDataTarget have them ordered correctly and we can use serializedProperties. + var validPlatforms = BuildPlatforms.instance.GetValidPlatforms().OrderBy(platform => platform.targetGroup); + settings.sampleSettingOverrides = new List(validPlatforms.Count()); foreach (BuildPlatform platform in validPlatforms) { - BuildTargetGroup platformGroup = platform.targetGroup; - - if (m_SampleSettingOverrides.ContainsKey(platformGroup)) + var groupName = platform.targetGroup.ToString(); + var sample = audioImporter.GetOverrideSampleSettings(groupName); + settings.sampleSettingOverrides.Add(new AudioImporterPlatformSettings() { - SampleSettingProperties overrideProperties = m_SampleSettingOverrides[platformGroup]; - - if (overrideProperties.overrideIsForced && !overrideProperties.forcedOverrideState) - { - importer.Internal_ClearSampleSettingOverride(platformGroup); - } - else if (importer.Internal_ContainsSampleSettingsOverride(platformGroup) || - (overrideProperties.overrideIsForced && overrideProperties.forcedOverrideState)) - { - AudioImporterSampleSettings overrideSettings = importer.Internal_GetOverrideSampleSettings(platformGroup); - - if (overrideProperties.loadTypeChanged) - overrideSettings.loadType = overrideProperties.settings.loadType; - - if (overrideProperties.sampleRateSettingChanged) - overrideSettings.sampleRateSetting = overrideProperties.settings.sampleRateSetting; - - if (overrideProperties.sampleRateOverrideChanged) - overrideSettings.sampleRateOverride = overrideProperties.settings.sampleRateOverride; - - if (overrideProperties.compressionFormatChanged) - overrideSettings.compressionFormat = overrideProperties.settings.compressionFormat; - - if (overrideProperties.qualityChanged) - overrideSettings.quality = overrideProperties.settings.quality; - - if (overrideProperties.conversionModeChanged) - overrideSettings.conversionMode = overrideProperties.settings.conversionMode; - - //Set the default settings on the importer after the changes. - importer.Internal_SetOverrideSampleSettings(platformGroup, overrideSettings); - } - - m_SampleSettingOverrides[platformGroup] = overrideProperties; - } + platform = platform.targetGroup, + isOverridden = audioImporter.ContainsSampleSettingsOverride(groupName), + settings = sample + }); } } + } - //Now that we are in sync with the backend, we need to clear the changed flags within - //the properties - m_DefaultSampleSettings.ClearChangedFlags(); - - foreach (BuildPlatform platform in validPlatforms) + private IEnumerable GetAllAudioImporterTargets() + { + foreach (Object importer in targets) { - BuildTargetGroup platformGroup = platform.targetGroup; - if (m_SampleSettingOverrides.ContainsKey(platformGroup)) - { - SampleSettingProperties overrideProperties = m_SampleSettingOverrides[platformGroup]; - overrideProperties.ClearChangedFlags(); - m_SampleSettingOverrides[platformGroup] = overrideProperties; - } + AudioImporter audioImporter = importer as AudioImporter; + if (audioImporter != null) + yield return audioImporter; } - - return true; } - private void ResetSettingsFromBackend() + private void SyncSettingsToBackend() { - if (GetAllAudioImporterTargets().Any()) + for (var index = 0; index < targets.Length; index++) { - AudioImporter firstImporter = GetAllAudioImporterTargets().First(); - //Just load the settings from the first importer for the default settings - m_DefaultSampleSettings.settings = firstImporter.defaultSampleSettings; - m_DefaultSampleSettings.ClearChangedFlags(); - - m_SampleSettingOverrides = new Dictionary(); - List validPlatforms = BuildPlatforms.instance.GetValidPlatforms(); - foreach (BuildPlatform platform in validPlatforms) + var audioImporter = targets[index] as AudioImporter; + var settings = extraDataTargets[index] as PlatformSettings; + if (settings != null && audioImporter != null) { - BuildTargetGroup platformGroup = platform.targetGroup; - foreach (AudioImporter importer in GetAllAudioImporterTargets()) + foreach (var setting in settings.sampleSettingOverrides) { - if (importer.Internal_ContainsSampleSettingsOverride(platformGroup)) + if (setting.isOverridden) { - SampleSettingProperties newProperties = new SampleSettingProperties(); - newProperties.settings = importer.Internal_GetOverrideSampleSettings(platformGroup); - - m_SampleSettingOverrides[platformGroup] = newProperties; - - //Just grab the first settings we find from any of the importers. - //This will be sorted later by checking if there are any differences between importers. - break; + audioImporter.SetOverrideSampleSettings(setting.platform.ToString(), setting.settings); + } + else if (audioImporter.ContainsSampleSettingsOverride(setting.platform.ToString())) + { + audioImporter.ClearSampleSettingOverride(setting.platform.ToString()); } - } - - //If we failed to find a valid override setting, just create a default one for use later. - if (!m_SampleSettingOverrides.ContainsKey(platformGroup)) - { - SampleSettingProperties newProperties = new SampleSettingProperties(); - newProperties.settings = firstImporter.Internal_GetOverrideSampleSettings(platformGroup); - - m_SampleSettingOverrides[platformGroup] = newProperties; } } } @@ -289,32 +176,27 @@ public override void OnEnable() m_OrigSize = serializedObject.FindProperty("m_PreviewData.m_OrigSize"); m_CompSize = serializedObject.FindProperty("m_PreviewData.m_CompSize"); - ResetSettingsFromBackend(); - } - - protected override void ResetValues() - { - base.ResetValues(); - ResetSettingsFromBackend(); - } + m_DefaultSampleSettings = serializedObject.FindProperty("m_DefaultSettings"); - public override void OnInspectorGUI() - { - serializedObject.Update(); - - bool selectionContainsTrackerFile = false; + m_SelectionContainsTrackerFile = false; foreach (AudioImporter importer in GetAllAudioImporterTargets()) { string assetPath = importer.assetPath; string ext = FileUtil.GetPathExtension(assetPath).ToLowerInvariant(); if (ext == "mod" || ext == "it" || ext == "s3m" || ext == "xm") { - selectionContainsTrackerFile = true; + m_SelectionContainsTrackerFile = true; break; } } + } - OnAudioImporterGUI(selectionContainsTrackerFile); + public override void OnInspectorGUI() + { + serializedObject.Update(); + extraDataSerializedObject.Update(); + + OnAudioImporterGUI(m_SelectionContainsTrackerFile); int origSize = 0, compSize = 0; foreach (AudioImporter importer in GetAllAudioImporterTargets()) @@ -328,7 +210,6 @@ public override void OnInspectorGUI() EditorGUILayout.HelpBox("Original Size: \t" + EditorUtility.FormatBytes(origSize) + "\nImported Size: \t" + EditorUtility.FormatBytes(compSize) + "\n" + "Ratio: \t\t" + (100.0f * (float)compSize / (float)origSize).ToString("0.00", CultureInfo.InvariantCulture.NumberFormat) + "%", MessageType.Info); - if (CurrentPlatformHasAutoTranslatedCompression()) { GUILayout.Space(10); @@ -341,90 +222,13 @@ public override void OnInspectorGUI() EditorGUILayout.HelpBox("The selection contains sounds that are decompressed in hardware. Advanced mixing is not available for these sounds.", MessageType.Info); } + extraDataSerializedObject.ApplyModifiedProperties(); serializedObject.ApplyModifiedProperties(); ApplyRevertGUI(); } - private MultiValueStatus GetMultiValueStatus(BuildTargetGroup platform) - { - MultiValueStatus status; - status.multiLoadType = false; - status.multiSampleRateSetting = false; - status.multiSampleRateOverride = false; - status.multiCompressionFormat = false; - status.multiQuality = false; - status.multiConversionMode = false; - - AudioImporterSampleSettings settings; - - if (GetAllAudioImporterTargets().Any()) - { - //We have at least one AudioImporter - AudioImporter firstImporter = GetAllAudioImporterTargets().First(); - - if (platform == BuildTargetGroup.Unknown) - settings = firstImporter.defaultSampleSettings; - else - settings = firstImporter.Internal_GetOverrideSampleSettings(platform); - - foreach (AudioImporter importer in GetAllAudioImporterTargets().Except(new[] {firstImporter})) - { - AudioImporterSampleSettings compareSettings; - if (platform == BuildTargetGroup.Unknown) - compareSettings = importer.defaultSampleSettings; - else - compareSettings = importer.Internal_GetOverrideSampleSettings(platform); - - status.multiLoadType |= settings.loadType != compareSettings.loadType; - status.multiSampleRateSetting |= settings.sampleRateSetting != compareSettings.sampleRateSetting; - status.multiSampleRateOverride |= settings.sampleRateOverride != compareSettings.sampleRateOverride; - status.multiCompressionFormat |= settings.compressionFormat != compareSettings.compressionFormat; - status.multiQuality |= settings.quality != compareSettings.quality; - status.multiConversionMode |= settings.conversionMode != compareSettings.conversionMode; - } - } - - return status; - } - - enum OverrideStatus - { - NoOverrides, - MixedOverrides, - AllOverrides - } - - private OverrideStatus GetOverrideStatus(BuildTargetGroup platform) - { - bool mixedOverrides = false; - bool containsOverride = false; - - if (GetAllAudioImporterTargets().Any()) - { - AudioImporter firstImporter = GetAllAudioImporterTargets().First(); - - containsOverride = firstImporter.Internal_ContainsSampleSettingsOverride(platform); - foreach (AudioImporter importer in GetAllAudioImporterTargets().Except(new[] {firstImporter})) - { - bool overrideState = importer.Internal_ContainsSampleSettingsOverride(platform); - - if (overrideState != containsOverride) - mixedOverrides |= true; - - containsOverride |= overrideState; - } - } - - if (!containsOverride) - return OverrideStatus.NoOverrides; - else if (mixedOverrides) - return OverrideStatus.MixedOverrides; - else - return OverrideStatus.AllOverrides; - } - - private AudioCompressionFormat[] GetFormatsForPlatform(BuildTargetGroup platform) + private List GetFormatsForPlatform(BuildTargetGroup platform) { List allowedFormats = new List(); @@ -432,7 +236,7 @@ private AudioCompressionFormat[] GetFormatsForPlatform(BuildTargetGroup platform if (platform == BuildTargetGroup.WebGL) { allowedFormats.Add(AudioCompressionFormat.AAC); - return allowedFormats.ToArray(); + return allowedFormats; } allowedFormats.Add(AudioCompressionFormat.PCM); @@ -457,7 +261,7 @@ private AudioCompressionFormat[] GetFormatsForPlatform(BuildTargetGroup platform if (platform == BuildTargetGroup.XboxOne) allowedFormats.Add(AudioCompressionFormat.XMA); - return allowedFormats.ToArray(); + return allowedFormats; } private bool CompressionFormatHasQuality(AudioCompressionFormat format) @@ -475,84 +279,137 @@ private bool CompressionFormatHasQuality(AudioCompressionFormat format) } } - private void OnSampleSettingGUI(BuildTargetGroup platform, MultiValueStatus status, bool selectionContainsTrackerFile, ref SampleSettingProperties properties, bool disablePreloadAudioDataOption) + private void OnSampleSettingGUI(BuildTargetGroup platform, SerializedProperty audioImporterSampleSettings, bool selectionContainsTrackerFile) { //Load Type - EditorGUI.showMixedValue = status.multiLoadType && !properties.loadTypeChanged; - EditorGUI.BeginChangeCheck(); - AudioClipLoadType newLoadType = (AudioClipLoadType)EditorGUILayout.EnumPopup("Load Type", properties.settings.loadType); - if (EditorGUI.EndChangeCheck()) + var loadTypeProperty = audioImporterSampleSettings.FindPropertyRelative("loadType"); + using (var horizontal = new EditorGUILayout.HorizontalScope()) { - properties.settings.loadType = newLoadType; - properties.loadTypeChanged = true; + using (var propertyScope = new EditorGUI.PropertyScope(horizontal.rect, Style.LoadType, loadTypeProperty)) + { + EditorGUI.showMixedValue = loadTypeProperty.hasMultipleDifferentValues; + using (var changed = new EditorGUI.ChangeCheckScope()) + { + var newValue = (AudioClipLoadType)EditorGUILayout.EnumPopup(propertyScope.content, (AudioClipLoadType)loadTypeProperty.intValue); + if (changed.changed) + { + loadTypeProperty.intValue = (int)newValue; + } + } + + EditorGUI.showMixedValue = false; + } } + //Preload Audio Data + // If the loadtype is streaming on the selected platform, gray out the "Preload Audio Data" option and show the checkbox as unchecked. + bool disablePreloadAudioDataOption = (AudioClipLoadType)loadTypeProperty.intValue == AudioClipLoadType.Streaming; using (new EditorGUI.DisabledScope(disablePreloadAudioDataOption)) { if (disablePreloadAudioDataOption) EditorGUILayout.Toggle("Preload Audio Data", false); else - EditorGUILayout.PropertyField(m_PreloadAudioData); + EditorGUILayout.PropertyField(m_PreloadAudioData, Style.PreloadAudioData); } if (!selectionContainsTrackerFile) { //Compression format - AudioCompressionFormat[] allowedFormats = GetFormatsForPlatform(platform); - EditorGUI.showMixedValue = status.multiCompressionFormat && !properties.compressionFormatChanged; - EditorGUI.BeginChangeCheck(); - AudioCompressionFormat newFormat = (AudioCompressionFormat)EditorGUILayout.IntPopup("Compression Format", - (int)properties.settings.compressionFormat, - Array.ConvertAll(allowedFormats, value => value.ToString()), - Array.ConvertAll(allowedFormats, value => (int)value)); - if (EditorGUI.EndChangeCheck()) + var compressionFormatProperty = audioImporterSampleSettings.FindPropertyRelative("compressionFormat"); + var allowedFormats = GetFormatsForPlatform(platform); + using (var horizontal = new EditorGUILayout.HorizontalScope()) { - properties.settings.compressionFormat = newFormat; - properties.compressionFormatChanged = true; + using (var propertyScope = new EditorGUI.PropertyScope(horizontal.rect, Style.CompressionFormat, compressionFormatProperty)) + { + EditorGUI.showMixedValue = compressionFormatProperty.hasMultipleDifferentValues; + using (var changed = new EditorGUI.ChangeCheckScope()) + { + var newValue = (AudioCompressionFormat)EditorGUILayout.IntPopup( + propertyScope.content, + compressionFormatProperty.intValue, + allowedFormats.Select(a => new GUIContent(a.ToString())).ToArray(), + allowedFormats.Select(a => (int)a).ToArray()); + if (changed.changed) + { + compressionFormatProperty.intValue = (int)newValue; + } + } + + EditorGUI.showMixedValue = false; + } } //Quality - if (CompressionFormatHasQuality(properties.settings.compressionFormat)) + if (!compressionFormatProperty.hasMultipleDifferentValues && CompressionFormatHasQuality((AudioCompressionFormat)compressionFormatProperty.intValue)) { - EditorGUI.showMixedValue = status.multiQuality && !properties.qualityChanged; - EditorGUI.BeginChangeCheck(); - int newQuality = EditorGUILayout.IntSlider("Quality", (int)Mathf.Clamp(properties.settings.quality * 100.0f, 1.0f, 100.0f), 1, 100); - if (EditorGUI.EndChangeCheck()) + using (var horizontal = new EditorGUILayout.HorizontalScope()) { - properties.settings.quality = 0.01f * newQuality; - properties.qualityChanged = true; + var property = audioImporterSampleSettings.FindPropertyRelative("quality"); + using (var propertyScope = new EditorGUI.PropertyScope(horizontal.rect, Style.Quality, property)) + { + EditorGUI.showMixedValue = property.hasMultipleDifferentValues; + using (var changed = new EditorGUI.ChangeCheckScope()) + { + var newValue = EditorGUILayout.IntSlider(propertyScope.content, (int)Mathf.Clamp(property.floatValue * 100.0f, 1.0f, 100.0f), 1, 100); + if (changed.changed) + { + property.floatValue = 0.01f * newValue; + } + } + + EditorGUI.showMixedValue = false; + } } } if (platform != BuildTargetGroup.WebGL) { //Sample rate settings - EditorGUI.showMixedValue = status.multiSampleRateSetting && !properties.sampleRateSettingChanged; - EditorGUI.BeginChangeCheck(); - AudioSampleRateSetting newSetting = (AudioSampleRateSetting)EditorGUILayout.EnumPopup("Sample Rate Setting", properties.settings.sampleRateSetting); - if (EditorGUI.EndChangeCheck()) + var sampleRateSettingProperty = audioImporterSampleSettings.FindPropertyRelative("sampleRateSetting"); + using (var horizontal = new EditorGUILayout.HorizontalScope()) { - properties.settings.sampleRateSetting = newSetting; - properties.sampleRateSettingChanged = true; + using (var propertyScope = new EditorGUI.PropertyScope(horizontal.rect, Style.SampleRateSetting, sampleRateSettingProperty)) + { + EditorGUI.showMixedValue = sampleRateSettingProperty.hasMultipleDifferentValues; + using (var changed = new EditorGUI.ChangeCheckScope()) + { + var newValue = (AudioSampleRateSetting)EditorGUILayout.EnumPopup(propertyScope.content, (AudioSampleRateSetting)sampleRateSettingProperty.intValue); + if (changed.changed) + { + sampleRateSettingProperty.intValue = (int)newValue; + } + } + + EditorGUI.showMixedValue = false; + } } - //Sample rate settings - if (properties.settings.sampleRateSetting == AudioSampleRateSetting.OverrideSampleRate) + //Sample rate override settings + if (!sampleRateSettingProperty.hasMultipleDifferentValues && (AudioSampleRateSetting)sampleRateSettingProperty.intValue == AudioSampleRateSetting.OverrideSampleRate) { - EditorGUI.showMixedValue = status.multiSampleRateOverride && !properties.sampleRateOverrideChanged; - EditorGUI.BeginChangeCheck(); - int newRate = EditorGUILayout.IntPopup("Sample Rate", (int)properties.settings.sampleRateOverride, - Styles.kSampleRateStrings, Styles.kSampleRateValues); - if (EditorGUI.EndChangeCheck()) + using (var horizontal = new EditorGUILayout.HorizontalScope()) { - properties.settings.sampleRateOverride = (uint)newRate; - properties.sampleRateOverrideChanged = true; + var property = audioImporterSampleSettings.FindPropertyRelative("sampleRateOverride"); + using (var propertyScope = new EditorGUI.PropertyScope(horizontal.rect, Style.SampleRate, property)) + { + EditorGUI.showMixedValue = property.hasMultipleDifferentValues; + using (var changed = new EditorGUI.ChangeCheckScope()) + { + var newValue = EditorGUILayout.IntPopup(propertyScope.content, property.intValue, + Style.kSampleRateStrings, Style.kSampleRateValues); + if (changed.changed) + { + property.intValue = newValue; + } + } + + EditorGUI.showMixedValue = false; + } } } } //TODO include the settings for things like HEVAG - EditorGUI.showMixedValue = false; } } @@ -573,74 +430,51 @@ private void OnAudioImporterGUI(bool selectionContainsTrackerFile) BuildPlatform[] validPlatforms = BuildPlatforms.instance.GetValidPlatforms().ToArray(); GUILayout.Space(10); - int shownSettingsPage = EditorGUILayout.BeginPlatformGrouping(validPlatforms, GUIContent.Temp("Default")); + int shownSettingsPage = EditorGUILayout.BeginPlatformGrouping(validPlatforms, Style.DefaultPlatform); if (shownSettingsPage == -1) { - // If the loadtype is streaming on the selected platform, gray out the "Preload Audio Data" option and show the checkbox as unchecked. - bool disablePreloadAudioDataOption = (m_DefaultSampleSettings.settings.loadType == AudioClipLoadType.Streaming); - - MultiValueStatus multiStatus = GetMultiValueStatus(BuildTargetGroup.Unknown); - OnSampleSettingGUI(BuildTargetGroup.Unknown, multiStatus, selectionContainsTrackerFile, ref m_DefaultSampleSettings, disablePreloadAudioDataOption); + OnSampleSettingGUI(BuildTargetGroup.Unknown, m_DefaultSampleSettings, selectionContainsTrackerFile); } else { BuildTargetGroup platform = validPlatforms[shownSettingsPage].targetGroup; - SampleSettingProperties properties = m_SampleSettingOverrides[platform]; - OverrideStatus status = GetOverrideStatus(platform); + SerializedProperty platformProperty = extraDataSerializedObject.FindProperty($"sampleSettingOverrides.Array.data[{shownSettingsPage}]"); + var isOverriddenProperty = platformProperty.FindPropertyRelative("isOverridden"); // Define the UI state of the override here. - EditorGUI.BeginChangeCheck(); - EditorGUI.showMixedValue = (status == OverrideStatus.MixedOverrides) && !properties.overrideIsForced; - bool overrideState = (properties.overrideIsForced && properties.forcedOverrideState) || - (!properties.overrideIsForced && status != OverrideStatus.NoOverrides); - overrideState = EditorGUILayout.ToggleLeft("Override for " + validPlatforms[shownSettingsPage].title.text, overrideState); - EditorGUI.showMixedValue = false; - if (EditorGUI.EndChangeCheck()) + using (var horizontal = new EditorGUILayout.HorizontalScope()) { - properties.forcedOverrideState = overrideState; - properties.overrideIsForced = true; - } - - // If the loadtype is streaming on the selected platform, gray out the "Preload Audio Data" option and show the checkbox as unchecked. - bool disablePreloadAudioDataOption = ((properties.overrideIsForced && properties.forcedOverrideState) || GetOverrideStatus(platform) == OverrideStatus.AllOverrides) && properties.settings.loadType == AudioClipLoadType.Streaming; + var label = EditorGUIUtility.TrTempContent("Override for " + validPlatforms[shownSettingsPage].title.text); + using (var propertyScope = new EditorGUI.PropertyScope(horizontal.rect, label, isOverriddenProperty)) + { + EditorGUI.showMixedValue = isOverriddenProperty.hasMultipleDifferentValues; + using (var changed = new EditorGUI.ChangeCheckScope()) + { + var newValue = EditorGUILayout.ToggleLeft(propertyScope.content, isOverriddenProperty.boolValue); + if (changed.changed) + { + isOverriddenProperty.boolValue = newValue; + } + } - MultiValueStatus multiStatus = GetMultiValueStatus(platform); - bool platformSettingsDisabled = !((properties.overrideIsForced && properties.forcedOverrideState) || status == OverrideStatus.AllOverrides); + EditorGUI.showMixedValue = false; + } + } - using (new EditorGUI.DisabledScope(platformSettingsDisabled)) + using (new EditorGUI.DisabledScope(isOverriddenProperty.hasMultipleDifferentValues || !isOverriddenProperty.boolValue)) { - OnSampleSettingGUI(platform, multiStatus, selectionContainsTrackerFile, ref properties, disablePreloadAudioDataOption); + OnSampleSettingGUI(platform, platformProperty.FindPropertyRelative("settings"), selectionContainsTrackerFile); } - - m_SampleSettingOverrides[platform] = properties; } EditorGUILayout.EndPlatformGrouping(); } - public override bool HasModified() - { - if (base.HasModified()) - return true; - - if (m_DefaultSampleSettings.HasModified()) - return true; - - //Iterate over all the override settings - Dictionary.ValueCollection valueColl = m_SampleSettingOverrides.Values; - foreach (SampleSettingProperties props in valueColl) - { - if (props.HasModified()) - return true; - } - - return false; - } - protected override void Apply() { base.Apply(); + SyncSettingsToBackend(); // This is necessary to enforce redrawing the static preview icons in the project browser, as properties like ForceToMono diff --git a/Modules/AssetPipelineEditor/ImportSettings/ModelImporterClipEditor.cs b/Modules/AssetPipelineEditor/ImportSettings/ModelImporterClipEditor.cs index 86949bd7fe..b1eff1cb36 100644 --- a/Modules/AssetPipelineEditor/ImportSettings/ModelImporterClipEditor.cs +++ b/Modules/AssetPipelineEditor/ImportSettings/ModelImporterClipEditor.cs @@ -112,7 +112,7 @@ private class Styles EditorGUIUtility.TrTextContent("Once", "The animation plays through to the end once and then stops."), EditorGUIUtility.TrTextContent("Loop", "The animation plays through and then restarts when the end is reached."), EditorGUIUtility.TrTextContent("PingPong", "The animation plays through and then plays in reverse from the end to the start, and so on."), - EditorGUIUtility.TrTextContent("ClampForever", "The animation plays through but the last frame is repeated indefinitely. This is not the same as Once mode because playback does not technically stop at the last frame (which is useful when blending animations).") + EditorGUIUtility.TrTextContent("ClampForever", "The animation plays through, but the last frame is repeated indefinitely. This is not the same as Once mode because playback does not technically stop at the last frame (which is useful when blending animations).") }; public GUIContent BakeIK = EditorGUIUtility.TrTextContent("Bake Animations", "Enable this when using IK or simulation in your animation package. Unity will convert to forward kinematics on import. This option is available only for Maya, 3dsMax and Cinema4D files."); @@ -253,6 +253,7 @@ void SyncClipEditor() m_AnimationClipEditor.ShowRange(info); m_AnimationClipEditor.mask = m_Mask; + AnimationCurvePreviewCache.ClearCache(); } private void SetupDefaultClips() diff --git a/Modules/AssetPipelineEditor/ImportSettings/ModelImporterEditor.cs b/Modules/AssetPipelineEditor/ImportSettings/ModelImporterEditor.cs index 9b75735040..3212e3061e 100644 --- a/Modules/AssetPipelineEditor/ImportSettings/ModelImporterEditor.cs +++ b/Modules/AssetPipelineEditor/ImportSettings/ModelImporterEditor.cs @@ -2,6 +2,10 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License +using System; +using System.IO; +using System.Linq; + using UnityEngine; using UnityEditor; @@ -13,6 +17,16 @@ internal class ModelImporterEditor : AssetImporterTabbedEditor { static string s_LocalizedTitle = L10n.Tr("Model Import Settings"); + static string s_C4DDeprecationWarning = L10n.Tr("Starting with the Unity 2019.3 release, direct import of Cinema4D files will require an external plugin. Keep an eye on our External Tools forum for updates.\n\nPlease note that FBX files exported from Cinema4D will still be supported."); + + public override void OnInspectorGUI() + { + if (targets.Any(t => t != null && Path.GetExtension(((AssetImporter)t).assetPath).Equals(".c4d", StringComparison.OrdinalIgnoreCase))) + EditorGUILayout.HelpBox(s_C4DDeprecationWarning, MessageType.Warning); + + base.OnInspectorGUI(); + } + public override void OnEnable() { if (tabs == null) diff --git a/Modules/AssetPipelineEditor/ImportSettings/ModelImporterMaterialEditor.cs b/Modules/AssetPipelineEditor/ImportSettings/ModelImporterMaterialEditor.cs index b40e43bb41..a38d0556bf 100644 --- a/Modules/AssetPipelineEditor/ImportSettings/ModelImporterMaterialEditor.cs +++ b/Modules/AssetPipelineEditor/ImportSettings/ModelImporterMaterialEditor.cs @@ -36,7 +36,6 @@ internal class ModelImporterMaterialEditor : BaseAssetImporterTabUI class ExternalObjectCache { - public SerializedProperty materialProp = null; public Material material = null; public int propertyIdx = 0; } @@ -186,6 +185,13 @@ internal override void OnEnable() BuildMaterialsCache(); BuildExternalObjectsCache(); } + Undo.undoRedoPerformed += ResetValues; + } + + internal override void OnDisable() + { + Undo.undoRedoPerformed -= ResetValues; + base.OnDisable(); } private void BuildMaterialsCache() @@ -218,8 +224,8 @@ private void BuildExternalObjectsCache() var pair = m_ExternalObjects.GetArrayElementAtIndex(externalObjectIdx); var cachedObject = new ExternalObjectCache(); - cachedObject.materialProp = pair.FindPropertyRelative("second"); - cachedObject.material = cachedObject.materialProp != null ? cachedObject.materialProp.objectReferenceValue as Material : null; + var materialProp = pair.FindPropertyRelative("second"); + cachedObject.material = materialProp != null ? materialProp.objectReferenceValue as Material : null; cachedObject.propertyIdx = externalObjectIdx; var externalName = pair.FindPropertyRelative("first.name").stringValue; var externalType = pair.FindPropertyRelative("first.type").stringValue; @@ -365,7 +371,7 @@ private bool ExtractMaterialsGUI() return false; } - private bool MaterialRemapOptons() + private bool MaterialRemapOptions() { m_ShowMaterialRemapOptions = EditorGUILayout.Foldout(m_ShowMaterialRemapOptions, Styles.RemapOptions); if (m_ShowMaterialRemapOptions) @@ -390,25 +396,16 @@ private bool MaterialRemapOptons() { if (GUILayout.Button(Styles.RemapMaterialsInProject)) { - try - { - AssetDatabase.StartAssetEditing(); - - foreach (var t in targets) - { - var importer = t as ModelImporter; - // SearchAndReplaceMaterials will ensure the material name and search options get saved, while all other pending changes stay pending. - importer.SearchAndRemapMaterials((ModelImporterMaterialName)m_MaterialName.intValue, (ModelImporterMaterialSearch)m_MaterialSearch.intValue); - - AssetDatabase.WriteImportSettingsIfDirty(importer.assetPath); - AssetDatabase.ImportAsset(importer.assetPath, ImportAssetOptions.ForceUpdate); - } - } - finally + foreach (var t in targets) { - AssetDatabase.StopAssetEditing(); + var importer = t as ModelImporter; + // SearchAndReplaceMaterials will ensure the material name and search options get saved, while all other pending changes stay pending. + importer.SearchAndRemapMaterials((ModelImporterMaterialName)m_MaterialName.intValue, (ModelImporterMaterialSearch)m_MaterialSearch.intValue); } + ResetValues(); + EditorGUIUtility.ExitGUI(); + return true; } } @@ -501,15 +498,14 @@ void DoMaterialsGUI() { GUILayout.Label(Styles.ExternalMaterialMappings, EditorStyles.boldLabel); - if (MaterialRemapOptons()) - return; - + MaterialRemapOptions(); DoMaterialRemapList(); } } internal override void ResetValues() { + serializedObject.Update(); BuildMaterialsCache(); BuildExternalObjectsCache(); } @@ -528,38 +524,40 @@ void DoMaterialRemapList() GUIContent nameLabel = EditorGUIUtility.TextContent(mat.name); nameLabel.tooltip = mat.name; - if (m_ExternalObjectsCache.TryGetValue(new Tuple(mat.name, mat.type), out cachedExternalObject)) + Material material = m_ExternalObjectsCache.TryGetValue(new Tuple(mat.name, mat.type), out cachedExternalObject) ? cachedExternalObject.material : null; + + EditorGUI.BeginChangeCheck(); + material = EditorGUILayout.ObjectField(nameLabel, material, typeof(Material), false) as Material; + if (EditorGUI.EndChangeCheck()) { - EditorGUI.BeginChangeCheck(); - EditorGUILayout.ObjectField(cachedExternalObject.materialProp, typeof(Material), nameLabel); - if (EditorGUI.EndChangeCheck()) + if (cachedExternalObject != null) { - if (cachedExternalObject.materialProp.objectReferenceValue == null) + if (material == null) { m_ExternalObjects.DeleteArrayElementAtIndex(cachedExternalObject.propertyIdx); - BuildExternalObjectsCache(); } - } - } - else - { - Material material = null; - EditorGUI.BeginChangeCheck(); - material = EditorGUILayout.ObjectField(nameLabel, material, typeof(Material), false) as Material; - if (EditorGUI.EndChangeCheck()) - { - if (material != null) + else { - var newIndex = m_ExternalObjects.arraySize++; - var pair = m_ExternalObjects.GetArrayElementAtIndex(newIndex); - pair.FindPropertyRelative("first.name").stringValue = mat.name; - pair.FindPropertyRelative("first.type").stringValue = mat.type; - pair.FindPropertyRelative("first.assembly").stringValue = mat.assembly; + var pair = m_ExternalObjects.GetArrayElementAtIndex(cachedExternalObject.propertyIdx); pair.FindPropertyRelative("second").objectReferenceValue = material; - - BuildExternalObjectsCache(); } } + else if (material != null) + { + m_ExternalObjects.arraySize++; + var pair = m_ExternalObjects.GetArrayElementAtIndex(m_ExternalObjects.arraySize - 1); + pair.FindPropertyRelative("first.name").stringValue = mat.name; + pair.FindPropertyRelative("first.type").stringValue = mat.type; + pair.FindPropertyRelative("first.assembly").stringValue = mat.assembly; + pair.FindPropertyRelative("second").objectReferenceValue = material; + // ExternalObjects is serialized as a map, so items are reordered when deserializing. + // We need to update the serializedObject to trigger the reordering before rebuilding the cache. + serializedObject.ApplyModifiedProperties(); + serializedObject.Update(); + } + + BuildExternalObjectsCache(); + break; } } } diff --git a/Modules/AssetPipelineEditor/ImportSettings/ModelImporterModelEditor.cs b/Modules/AssetPipelineEditor/ImportSettings/ModelImporterModelEditor.cs index 361a145686..a25492512e 100644 --- a/Modules/AssetPipelineEditor/ImportSettings/ModelImporterModelEditor.cs +++ b/Modules/AssetPipelineEditor/ImportSettings/ModelImporterModelEditor.cs @@ -122,7 +122,7 @@ protected static class Styles public static GUIContent NormalsLabel = EditorGUIUtility.TrTextContent("Normals", "Source of mesh normals. If Import is selected and a mesh has no normals, they will be calculated instead."); public static GUIContent RecalculateNormalsLabel = EditorGUIUtility.TrTextContent("Normals Mode", "How to weight faces when calculating normals."); - public static GUIContent SmoothingAngle = EditorGUIUtility.TrTextContent("Smoothing Angle", "When calculating normals on a mesh that doesn’t have smoothing groups, edges between faces will be smooth if this value is greater than the angle between the faces."); + public static GUIContent SmoothingAngle = EditorGUIUtility.TrTextContent("Smoothing Angle", "When calculating normals on a mesh that doesn't have smoothing groups, edges between faces will be smooth if this value is greater than the angle between the faces."); public static GUIContent TangentsLabel = EditorGUIUtility.TrTextContent("Tangents", "Source of mesh tangents. If Import is selected and a mesh has no tangents, they will be calculated instead."); diff --git a/Modules/AssetPipelineEditor/ImportSettings/ModelImporterRigEditor.cs b/Modules/AssetPipelineEditor/ImportSettings/ModelImporterRigEditor.cs index 0991b498b6..fa84a328ae 100644 --- a/Modules/AssetPipelineEditor/ImportSettings/ModelImporterRigEditor.cs +++ b/Modules/AssetPipelineEditor/ImportSettings/ModelImporterRigEditor.cs @@ -99,7 +99,7 @@ static class Styles public static GUIContent UpdateMuscleDefinitionFromSource = EditorGUIUtility.TrTextContent("Update", "Update the copy of the muscle definition from the source."); public static GUIContent RootNode = EditorGUIUtility.TrTextContent("Root node", "Specify the root node used to extract the animation translation."); - public static GUIContent AvatarDefinition = EditorGUIUtility.TrTextContent("Avatar Definition", "Choose between Create From This Model or Copy From Other Avatar. The first one create an Avatar for this file and the second one use an Avatar from another file to import animation."); + public static GUIContent AvatarDefinition = EditorGUIUtility.TrTextContent("Avatar Definition", "Choose between Create From This Model or Copy From Other Avatar. The first one creates an Avatar for this file and the second one uses an Avatar from another file to import animation."); public static GUIContent[] AvatarDefinitionOpt = { @@ -116,10 +116,10 @@ static class Styles public static GUIContent MaxBonesPerVertex = EditorGUIUtility.TrTextContent("Max Bones/Vertex", "Number of bones that can affect each vertex."); public static GUIContent MinBoneWeight = EditorGUIUtility.TrTextContent("Min Bone Weight", "Bone weights smaller than this value are rejected. The remaining weights are scaled to add up to 1.0."); - public static GUIContent UpdateReferenceClips = EditorGUIUtility.TrTextContent("Update reference clips", "Click on this button to update all the @convention file referencing this file. Should set all these files to Copy From Other Avatar, set the source Avatar to this one and reimport all these files."); + public static GUIContent UpdateReferenceClips = EditorGUIUtility.TrTextContent("Update reference clips", "Click on this button to update all the @convention files referencing this file. Should set all these files to Copy From Other Avatar, set the source Avatar to this one and reimport all these files."); public static GUIContent ImportMessages = EditorGUIUtility.TrTextContent("Import Messages"); - public static GUIContent ExtraExposedTransform = EditorGUIUtility.TrTextContent("Extra Transforms to Expose", "Select the list of transforms to expose in the optmized GameObject hierarchy."); + public static GUIContent ExtraExposedTransform = EditorGUIUtility.TrTextContent("Extra Transforms to Expose", "Select the list of transforms to expose in the optimized GameObject hierarchy."); } public ModelImporterRigEditor(AssetImporterEditor panelContainer) @@ -278,18 +278,27 @@ void GenericGUI() EditorGUI.BeginChangeCheck(); using (new EditorGUI.DisabledScope(!m_CanMultiEditTransformList)) { - rootIndex = EditorGUILayout.Popup(Styles.RootNode, rootIndex, m_RootMotionBoneList); - } - if (EditorGUI.EndChangeCheck()) - { - if (rootIndex > 0 && rootIndex < m_RootMotionBoneList.Length) + if (assetTarget == null) { m_RootMotionBoneName.stringValue = - FileUtil.GetLastPathNameComponent(m_RootMotionBoneList[rootIndex].text); + EditorGUILayout.TextField(Styles.RootNode, m_RootMotionBoneName.stringValue); } else + rootIndex = EditorGUILayout.Popup(Styles.RootNode, rootIndex, m_RootMotionBoneList); + } + if (EditorGUI.EndChangeCheck()) + { + if (assetTarget != null) { - m_RootMotionBoneName.stringValue = ""; + if (rootIndex > 0 && rootIndex < m_RootMotionBoneList.Length) + { + m_RootMotionBoneName.stringValue = + FileUtil.GetLastPathNameComponent(m_RootMotionBoneList[rootIndex].text); + } + else + { + m_RootMotionBoneName.stringValue = ""; + } } } } diff --git a/Modules/AssetPipelineEditor/ImportSettings/VideoClipImporterInspector.cs b/Modules/AssetPipelineEditor/ImportSettings/VideoClipImporterInspector.cs index faa4487c8c..278d0090b7 100644 --- a/Modules/AssetPipelineEditor/ImportSettings/VideoClipImporterInspector.cs +++ b/Modules/AssetPipelineEditor/ImportSettings/VideoClipImporterInspector.cs @@ -2,18 +2,16 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using AnimatedBool = UnityEditor.AnimatedValues.AnimBool; +using System; using System.Collections.Generic; -using UnityEditor; -using UnityEditorInternal; -using UnityEngine; +using System.Globalization; +using System.IO; +using System.Linq; +using UnityEditor.AnimatedValues; using UnityEditor.Build; -using System; using UnityEditor.Experimental.AssetImporters; -using Math = System.Math; -using Path = System.IO.Path; -using System.Globalization; +using UnityEngine; +using Object = UnityEngine.Object; namespace UnityEditor { @@ -128,52 +126,17 @@ private void ShowProperty(ref Rect labelRect, ref Rect valueRect, string label, [CanEditMultipleObjects] internal class VideoClipImporterInspector : AssetImporterEditor { - internal struct MultiTargetSettingState + [Serializable] + class InspectorTargetSettings { - public void Init() - { - mixedTranscoding = false; - mixedCodec = false; - mixedResizeMode = false; - mixedAspectRatio = false; - mixedCustomWidth = false; - mixedCustomHeight = false; - mixedBitrateMode = false; - mixedSpatialQuality = false; - - firstTranscoding = false; - firstCodec = VideoCodec.Auto; - firstResizeMode = VideoResizeMode.OriginalSize; - firstAspectRatio = VideoEncodeAspectRatio.NoScaling; - firstCustomWidth = -1; - firstCustomHeight = -1; - firstBitrateMode = VideoBitrateMode.High; - firstSpatialQuality = VideoSpatialQuality.HighSpatialQuality; - } - - public bool mixedTranscoding; - public bool mixedCodec; - public bool mixedResizeMode; - public bool mixedAspectRatio; - public bool mixedCustomWidth; - public bool mixedCustomHeight; - public bool mixedBitrateMode; - public bool mixedSpatialQuality; - - public bool firstTranscoding; - public VideoCodec firstCodec; - public VideoResizeMode firstResizeMode; - public VideoEncodeAspectRatio firstAspectRatio; - public int firstCustomWidth; - public int firstCustomHeight; - public VideoBitrateMode firstBitrateMode; - public VideoSpatialQuality firstSpatialQuality; + public bool overridePlatform; + public BuildTargetGroup target; + public VideoImporterTargetSettings settings; } - internal class InspectorTargetSettings + class TargetSettings : ScriptableObject { - public bool overridePlatform; - public VideoImporterTargetSettings settings; + public List allSettings; } SerializedProperty m_UseLegacyImporter; @@ -187,13 +150,9 @@ internal class InspectorTargetSettings SerializedProperty m_ImportAudio; SerializedProperty m_ColorSpace; - // An array of settings for each platform, for every target. - InspectorTargetSettings[,] m_TargetSettings; - bool m_IsPlaying = false; Vector2 m_Position = Vector2.zero; - AnimatedBool m_ShowResizeModeOptions = new AnimatedBool(); - bool m_ModifiedTargetSettings; + AnimBool m_ShowResizeModeOptions = new AnimBool(); Texture m_Texture; GUIContent m_PreviewTitle; @@ -262,61 +221,60 @@ class Styles // Don't show the imported movie as a separate editor public override bool showImportedObject { get { return false; } } - private void ResetSettingsFromBackend() + protected override Type extraDataType => typeof(TargetSettings); + + protected override void InitializeExtraDataInstance(Object extraData, int targetIndex) { - m_TargetSettings = null; - if (targets.Length > 0) + var targetSettings = extraData as TargetSettings; + var currentTarget = targets[targetIndex] as VideoClipImporter; + if (targetSettings != null && currentTarget != null) { - List validPlatforms = BuildPlatforms.instance.GetValidPlatforms(); - m_TargetSettings = new InspectorTargetSettings[targets.Length, validPlatforms.Count + 1]; - - for (int i = 0; i < targets.Length; i++) - { - VideoClipImporter clipImporter = (VideoClipImporter)targets[i]; + var validPlatforms = BuildPlatforms.instance.GetValidPlatforms(); + targetSettings.allSettings = new List(validPlatforms.Count() + 1); - m_TargetSettings[i, 0] = new InspectorTargetSettings(); - m_TargetSettings[i, 0].overridePlatform = true; - m_TargetSettings[i, 0].settings = clipImporter.defaultTargetSettings; + var defaultSetting = new InspectorTargetSettings(); + defaultSetting.target = BuildTargetGroup.Unknown; + defaultSetting.settings = currentTarget.defaultTargetSettings; + defaultSetting.overridePlatform = true; + targetSettings.allSettings.Add(defaultSetting); - for (int j = 1; j < validPlatforms.Count + 1; j++) + foreach (var validPlatform in validPlatforms) + { + var setting = new InspectorTargetSettings(); + setting.target = validPlatform.targetGroup; + setting.settings = currentTarget.Internal_GetTargetSettings(validPlatform.targetGroup); + setting.overridePlatform = setting.settings != null; + if (!setting.overridePlatform) { - BuildTargetGroup platformGroup = validPlatforms[j - 1].targetGroup; - m_TargetSettings[i, j] = new InspectorTargetSettings(); - m_TargetSettings[i, j].settings = clipImporter.Internal_GetTargetSettings(platformGroup); - - // We need to use this flag, and the nullity of the settings to determine if - // we have an override. This is because we could create an override later during a toggle - // and we want to keep that override even if we untoggle (to not lose the changes made) - m_TargetSettings[i, j].overridePlatform = m_TargetSettings[i, j].settings != null; + setting.settings = currentTarget.defaultTargetSettings; } + targetSettings.allSettings.Add(setting); } } - - m_ModifiedTargetSettings = false; } private void WriteSettingsToBackend() { - if (m_TargetSettings != null) + for (var i = 0; i < extraDataTargets.Length; i++) { - List validPlatforms = BuildPlatforms.instance.GetValidPlatforms(); - for (int i = 0; i < targets.Length; i++) + var dataTarget = extraDataTargets[i] as TargetSettings; + var importer = targets[i] as VideoClipImporter; + + if (dataTarget != null && importer != null) { - VideoClipImporter clipImporter = (VideoClipImporter)targets[i]; - clipImporter.defaultTargetSettings = m_TargetSettings[i, 0].settings; + var defaultSettings = dataTarget.allSettings[0]; + importer.defaultTargetSettings = defaultSettings.settings; - for (int j = 1; j < validPlatforms.Count + 1; j++) + for (var j = 1; j < dataTarget.allSettings.Count; j++) { - BuildTargetGroup platformGroup = validPlatforms[j - 1].targetGroup; - if (m_TargetSettings[i, j].settings != null && m_TargetSettings[i, j].overridePlatform) - clipImporter.Internal_SetTargetSettings(platformGroup, m_TargetSettings[i, j].settings); + var setting = dataTarget.allSettings[j]; + if (setting.overridePlatform) + importer.Internal_SetTargetSettings(setting.target, setting.settings); else - clipImporter.Internal_ClearTargetSettings(platformGroup); + importer.Internal_ClearTargetSettings(setting.target); } } } - - m_ModifiedTargetSettings = false; } public override void OnEnable() @@ -336,18 +294,9 @@ public override void OnEnable() m_ImportAudio = serializedObject.FindProperty("m_ImportAudio"); m_ColorSpace = serializedObject.FindProperty("m_ColorSpace"); - ResetBackendValues(); - } - - void ResetBackendValues() - { - ResetSettingsFromBackend(); - - // We need to do this so we can calculate the correct fade state - MultiTargetSettingState state = CalculateMultiTargetSettingState(0); - m_ShowResizeModeOptions.valueChanged.AddListener(Repaint); - m_ShowResizeModeOptions.value = state.mixedResizeMode || (state.firstResizeMode != VideoResizeMode.OriginalSize); + var defaultResizeMode = extraDataSerializedObject.FindProperty("allSettings.Array.data[0].settings.resizeMode"); + m_ShowResizeModeOptions.value = defaultResizeMode.hasMultipleDifferentValues || (VideoResizeMode)defaultResizeMode.intValue != VideoResizeMode.OriginalSize; } public override void OnDisable() @@ -358,25 +307,16 @@ public override void OnDisable() base.OnDisable(); } - private List GetResizeModeList() - { - var resizeModeList = new List(); - VideoClipImporter importer = (VideoClipImporter)target; - foreach (VideoResizeMode mode in System.Enum.GetValues(typeof(VideoResizeMode))) - resizeModeList.Add(EditorGUIUtility.TextContent(importer.GetResizeModeName(mode))); - - return resizeModeList; - } - private bool AnySettingsNotTranscoded() { - if (m_TargetSettings != null) + foreach (var extraData in extraDataTargets) { - for (int i = 0; i < m_TargetSettings.GetLength(0); i++) + var settings = extraData as TargetSettings; + if (settings != null) { - for (int j = 0; j < m_TargetSettings.GetLength(1); j++) + foreach (var setting in settings.allSettings) { - if (m_TargetSettings[i, j].settings != null && !m_TargetSettings[i, j].settings.enableTranscoding) + if (setting.overridePlatform && !setting.settings.enableTranscoding) return true; } } @@ -385,64 +325,6 @@ private bool AnySettingsNotTranscoded() return false; } - private MultiTargetSettingState CalculateMultiTargetSettingState(int platformIndex) - { - MultiTargetSettingState state = new MultiTargetSettingState(); - state.Init(); - - if (m_TargetSettings == null || m_TargetSettings.Length == 0) - return state; - - int firstValidIndex = -1; - for (int i = 0; i < m_TargetSettings.GetLength(0); i++) - { - if (m_TargetSettings[i, platformIndex].overridePlatform) - { - if (firstValidIndex == -1) - { - firstValidIndex = i; - - state.firstTranscoding = m_TargetSettings[i, platformIndex].settings.enableTranscoding; - state.firstCodec = m_TargetSettings[i, platformIndex].settings.codec; - state.firstResizeMode = m_TargetSettings[i, platformIndex].settings.resizeMode; - state.firstAspectRatio = m_TargetSettings[i, platformIndex].settings.aspectRatio; - state.firstCustomWidth = m_TargetSettings[i, platformIndex].settings.customWidth; - state.firstCustomHeight = m_TargetSettings[i, platformIndex].settings.customHeight; - state.firstBitrateMode = m_TargetSettings[i, platformIndex].settings.bitrateMode; - state.firstSpatialQuality = m_TargetSettings[i, platformIndex].settings.spatialQuality; - } - else - { - state.mixedTranscoding = state.firstTranscoding != m_TargetSettings[i, platformIndex].settings.enableTranscoding; - state.mixedCodec = state.firstCodec != m_TargetSettings[i, platformIndex].settings.codec; - state.mixedResizeMode = state.firstResizeMode != m_TargetSettings[i, platformIndex].settings.resizeMode; - state.mixedAspectRatio = state.firstAspectRatio != m_TargetSettings[i, platformIndex].settings.aspectRatio; - state.mixedCustomWidth = state.firstCustomWidth != m_TargetSettings[i, platformIndex].settings.customWidth; - state.mixedCustomHeight = state.firstCustomHeight != m_TargetSettings[i, platformIndex].settings.customHeight; - state.mixedBitrateMode = state.firstBitrateMode != m_TargetSettings[i, platformIndex].settings.bitrateMode; - state.mixedSpatialQuality = state.firstSpatialQuality != m_TargetSettings[i, platformIndex].settings.spatialQuality; - } - } - } - - // If there are no override settings for this platform for ANY of the targets, - // then just get the default settings and use those. - if (firstValidIndex == -1) - { - // The default settings are always valid - state.firstTranscoding = m_TargetSettings[0, 0].settings.enableTranscoding; - state.firstCodec = m_TargetSettings[0, 0].settings.codec; - state.firstResizeMode = m_TargetSettings[0, 0].settings.resizeMode; - state.firstAspectRatio = m_TargetSettings[0, 0].settings.aspectRatio; - state.firstCustomWidth = m_TargetSettings[0, 0].settings.customWidth; - state.firstCustomHeight = m_TargetSettings[0, 0].settings.customHeight; - state.firstBitrateMode = m_TargetSettings[0, 0].settings.bitrateMode; - state.firstSpatialQuality = m_TargetSettings[0, 0].settings.spatialQuality; - } - - return state; - } - private void OnCrossTargetInspectorGUI() { bool sourcesHaveAlpha = true; @@ -478,79 +360,56 @@ private void OnCrossTargetInspectorGUI() } } - private void FrameSettingsGUI(int platformIndex, MultiTargetSettingState multiState) + private void FrameSettingsGUI(SerializedProperty videoImporterTargetSettings) { - EditorGUI.showMixedValue = multiState.mixedResizeMode; - EditorGUI.BeginChangeCheck(); - VideoResizeMode resizeMode = (VideoResizeMode)EditorGUILayout.Popup(s_Styles.dimensionsContent, (int)multiState.firstResizeMode, GetResizeModeList().ToArray()); - EditorGUI.showMixedValue = false; - if (EditorGUI.EndChangeCheck()) + var resizeModeProperty = videoImporterTargetSettings.FindPropertyRelative("resizeMode"); + using (var horizontal = new EditorGUILayout.HorizontalScope()) { - for (int i = 0; i < m_TargetSettings.GetLength(0); i++) + using (var propertyScope = new EditorGUI.PropertyScope(horizontal.rect, s_Styles.dimensionsContent, resizeModeProperty)) { - if (m_TargetSettings[i, platformIndex].settings != null) + using (var changed = new EditorGUI.ChangeCheckScope()) { - m_TargetSettings[i, platformIndex].settings.resizeMode = resizeMode; - m_ModifiedTargetSettings = true; + EditorGUI.showMixedValue = resizeModeProperty.hasMultipleDifferentValues; + var resizeMode = (VideoResizeMode)EditorGUILayout.EnumPopup(propertyScope.content, (VideoResizeMode)resizeModeProperty.intValue); + EditorGUI.showMixedValue = false; + if (changed.changed) + { + resizeModeProperty.intValue = (int)resizeMode; + } } } } // First item is "Original". Options appear if another resize mode is chosen. - m_ShowResizeModeOptions.target = resizeMode != VideoResizeMode.OriginalSize; + var resizeValue = (VideoResizeMode)resizeModeProperty.intValue; + m_ShowResizeModeOptions.target = resizeModeProperty.hasMultipleDifferentValues || resizeValue != VideoResizeMode.OriginalSize; if (EditorGUILayout.BeginFadeGroup(m_ShowResizeModeOptions.faded)) { EditorGUI.indentLevel++; - if (resizeMode == VideoResizeMode.CustomSize) + if (!resizeModeProperty.hasMultipleDifferentValues && resizeValue == VideoResizeMode.CustomSize) { - EditorGUI.showMixedValue = multiState.mixedCustomWidth; - EditorGUI.BeginChangeCheck(); - int customWidth = EditorGUILayout.IntField(s_Styles.widthContent, multiState.firstCustomWidth); - customWidth = Mathf.Clamp(customWidth, kMinCustomWidth, kMaxCustomWidth); - EditorGUI.showMixedValue = false; - if (EditorGUI.EndChangeCheck()) - { - for (int i = 0; i < m_TargetSettings.GetLength(0); i++) - { - if (m_TargetSettings[i, platformIndex].settings != null) - { - m_TargetSettings[i, platformIndex].settings.customWidth = customWidth; - m_ModifiedTargetSettings = true; - } - } - } + var customWidthProperty = videoImporterTargetSettings.FindPropertyRelative("customWidth"); + EditorGUILayout.PropertyField(customWidthProperty, s_Styles.widthContent); - EditorGUI.showMixedValue = multiState.mixedCustomHeight; - EditorGUI.BeginChangeCheck(); - int customHeight = EditorGUILayout.IntField(s_Styles.heightContent, multiState.firstCustomHeight); - customHeight = Mathf.Clamp(customHeight, kMinCustomHeight, kMaxCustomHeight); - EditorGUI.showMixedValue = false; - if (EditorGUI.EndChangeCheck()) - { - for (int i = 0; i < m_TargetSettings.GetLength(0); i++) - { - if (m_TargetSettings[i, platformIndex].settings != null) - { - m_TargetSettings[i, platformIndex].settings.customHeight = customHeight; - m_ModifiedTargetSettings = true; - } - } - } + var customHeightProperty = videoImporterTargetSettings.FindPropertyRelative("customHeight"); + EditorGUILayout.PropertyField(customHeightProperty, s_Styles.heightContent); } - EditorGUI.showMixedValue = multiState.mixedAspectRatio; - EditorGUI.BeginChangeCheck(); - VideoEncodeAspectRatio aspectRatio = (VideoEncodeAspectRatio)EditorGUILayout.EnumPopup(s_Styles.aspectRatioContent, multiState.firstAspectRatio); - EditorGUI.showMixedValue = false; - if (EditorGUI.EndChangeCheck()) + using (var horizontal = new EditorGUILayout.HorizontalScope()) { - for (int i = 0; i < m_TargetSettings.GetLength(0); i++) + var property = videoImporterTargetSettings.FindPropertyRelative("aspectRatio"); + using (var propertyScope = new EditorGUI.PropertyScope(horizontal.rect, s_Styles.aspectRatioContent, property)) { - if (m_TargetSettings[i, platformIndex].settings != null) + using (var changed = new EditorGUI.ChangeCheckScope()) { - m_TargetSettings[i, platformIndex].settings.aspectRatio = aspectRatio; - m_ModifiedTargetSettings = true; + EditorGUI.showMixedValue = property.hasMultipleDifferentValues; + var newValue = (VideoEncodeAspectRatio)EditorGUILayout.EnumPopup(propertyScope.content, (VideoEncodeAspectRatio)property.intValue); + EditorGUI.showMixedValue = false; + if (changed.changed) + { + property.intValue = (int)newValue; + } } } } @@ -561,113 +420,74 @@ private void FrameSettingsGUI(int platformIndex, MultiTargetSettingState multiSt EditorGUILayout.EndFadeGroup(); } - private void EncodingSettingsGUI(int platformIndex, MultiTargetSettingState multiState) + private void EncodingSettingsGUI(SerializedProperty videoImporterTargetSettings) { - EditorGUI.showMixedValue = multiState.mixedCodec; - EditorGUI.BeginChangeCheck(); - VideoCodec codec = (VideoCodec)EditorGUILayout.EnumPopup(s_Styles.codecContent, multiState.firstCodec); - EditorGUI.showMixedValue = false; - if (EditorGUI.EndChangeCheck()) + using (var horizontal = new EditorGUILayout.HorizontalScope()) { - for (int i = 0; i < m_TargetSettings.GetLength(0); i++) + var property = videoImporterTargetSettings.FindPropertyRelative("codec"); + using (var propertyScope = new EditorGUI.PropertyScope(horizontal.rect, s_Styles.codecContent, property)) { - if (m_TargetSettings[i, platformIndex].settings != null) + using (var changed = new EditorGUI.ChangeCheckScope()) { - m_TargetSettings[i, platformIndex].settings.codec = codec; - m_ModifiedTargetSettings = true; + EditorGUI.showMixedValue = property.hasMultipleDifferentValues; + var newValue = (VideoCodec)EditorGUILayout.EnumPopup(propertyScope.content, (VideoCodec)property.intValue); + EditorGUI.showMixedValue = false; + if (changed.changed) + { + property.intValue = (int)newValue; + } } } } - EditorGUI.showMixedValue = multiState.mixedBitrateMode; - EditorGUI.BeginChangeCheck(); - VideoBitrateMode bitrateMode = (VideoBitrateMode)EditorGUILayout.EnumPopup(s_Styles.bitrateContent, multiState.firstBitrateMode); - EditorGUI.showMixedValue = false; - if (EditorGUI.EndChangeCheck()) + using (var horizontal = new EditorGUILayout.HorizontalScope()) { - for (int i = 0; i < m_TargetSettings.GetLength(0); i++) + var property = videoImporterTargetSettings.FindPropertyRelative("bitrateMode"); + using (var propertyScope = new EditorGUI.PropertyScope(horizontal.rect, s_Styles.bitrateContent, property)) { - if (m_TargetSettings[i, platformIndex].settings != null) + using (var changed = new EditorGUI.ChangeCheckScope()) { - m_TargetSettings[i, platformIndex].settings.bitrateMode = bitrateMode; - m_ModifiedTargetSettings = true; + EditorGUI.showMixedValue = property.hasMultipleDifferentValues; + var newValue = (VideoBitrateMode)EditorGUILayout.EnumPopup(propertyScope.content, (VideoBitrateMode)property.intValue); + EditorGUI.showMixedValue = false; + if (changed.changed) + { + property.intValue = (int)newValue; + } } } } - EditorGUI.showMixedValue = multiState.mixedSpatialQuality; - EditorGUI.BeginChangeCheck(); - VideoSpatialQuality spatialQuality = (VideoSpatialQuality)EditorGUILayout.EnumPopup(s_Styles.spatialQualityContent, multiState.firstSpatialQuality); - EditorGUI.showMixedValue = false; - if (EditorGUI.EndChangeCheck()) + using (var horizontal = new EditorGUILayout.HorizontalScope()) { - for (int i = 0; i < m_TargetSettings.GetLength(0); i++) + var property = videoImporterTargetSettings.FindPropertyRelative("spatialQuality"); + using (var propertyScope = new EditorGUI.PropertyScope(horizontal.rect, s_Styles.spatialQualityContent, property)) { - if (m_TargetSettings[i, platformIndex].settings != null) + using (var changed = new EditorGUI.ChangeCheckScope()) { - m_TargetSettings[i, platformIndex].settings.spatialQuality = spatialQuality; - m_ModifiedTargetSettings = true; + EditorGUI.showMixedValue = property.hasMultipleDifferentValues; + var newValue = (VideoSpatialQuality)EditorGUILayout.EnumPopup(propertyScope.content, (VideoSpatialQuality)property.intValue); + EditorGUI.showMixedValue = false; + if (changed.changed) + { + property.intValue = (int)newValue; + } } } } } - private bool HasMixedOverrideStatus(int platformIndex, out bool overrideState) - { - overrideState = false; - if (m_TargetSettings == null || m_TargetSettings.Length == 0) - return false; - - overrideState = m_TargetSettings[0, platformIndex].overridePlatform; - for (int i = 1; i < m_TargetSettings.GetLength(0); i++) - { - if (m_TargetSettings[i, platformIndex].overridePlatform != overrideState) - return true; - } - - return false; - } - - private VideoImporterTargetSettings CloneTargetSettings(VideoImporterTargetSettings settings) + private void OnTargetSettingsInspectorGUI(SerializedProperty videoImporterTargetSettings) { - VideoImporterTargetSettings newSettings = new VideoImporterTargetSettings(); - - newSettings.enableTranscoding = settings.enableTranscoding; - newSettings.codec = settings.codec; - newSettings.resizeMode = settings.resizeMode; - newSettings.aspectRatio = settings.aspectRatio; - newSettings.customWidth = settings.customWidth; - newSettings.customHeight = settings.customHeight; - newSettings.bitrateMode = settings.bitrateMode; - newSettings.spatialQuality = settings.spatialQuality; - - return newSettings; - } - - private void OnTargetSettingsInspectorGUI(int platformIndex, MultiTargetSettingState multiState) - { - EditorGUI.showMixedValue = multiState.mixedTranscoding; - EditorGUI.BeginChangeCheck(); - bool transcode = EditorGUILayout.Toggle(s_Styles.transcodeContent, multiState.firstTranscoding); - EditorGUI.showMixedValue = false; - if (EditorGUI.EndChangeCheck()) - { - for (int i = 0; i < m_TargetSettings.GetLength(0); i++) - { - if (m_TargetSettings[i, platformIndex].settings != null) - { - m_TargetSettings[i, platformIndex].settings.enableTranscoding = transcode; - m_ModifiedTargetSettings = true; - } - } - } + var enableTranscodingProperty = videoImporterTargetSettings.FindPropertyRelative("enableTranscoding"); + EditorGUILayout.PropertyField(enableTranscodingProperty, s_Styles.transcodeContent); EditorGUI.indentLevel++; - using (new EditorGUI.DisabledScope(!(transcode || multiState.mixedTranscoding))) + using (new EditorGUI.DisabledScope(!(enableTranscodingProperty.boolValue || enableTranscodingProperty.hasMultipleDifferentValues))) { - FrameSettingsGUI(platformIndex, multiState); - EncodingSettingsGUI(platformIndex, multiState); + FrameSettingsGUI(videoImporterTargetSettings); + EncodingSettingsGUI(videoImporterTargetSettings); } EditorGUI.indentLevel--; @@ -675,33 +495,29 @@ private void OnTargetSettingsInspectorGUI(int platformIndex, MultiTargetSettingS private void OnTargetInspectorGUI(int platformIndex, string platformName) { - bool enableOverrideSettings = true; + var inspectorTargetSettings = extraDataSerializedObject.FindProperty($"allSettings.Array.data[{platformIndex}]"); + var overrideEnabled = inspectorTargetSettings.FindPropertyRelative("overridePlatform"); if (platformIndex != 0) { - bool overrideState; - EditorGUI.showMixedValue = HasMixedOverrideStatus(platformIndex, out overrideState); + EditorGUI.showMixedValue = overrideEnabled.hasMultipleDifferentValues; EditorGUI.BeginChangeCheck(); - overrideState = EditorGUILayout.Toggle("Override for " + platformName, overrideState); - enableOverrideSettings = overrideState || EditorGUI.showMixedValue; + var newValue = EditorGUILayout.Toggle("Override for " + platformName, overrideEnabled.boolValue); EditorGUI.showMixedValue = false; if (EditorGUI.EndChangeCheck()) { - for (int i = 0; i < m_TargetSettings.GetLength(0); i++) + overrideEnabled.boolValue = newValue; + if (!newValue) { - m_TargetSettings[i, platformIndex].overridePlatform = overrideState; - m_ModifiedTargetSettings = true; - if (m_TargetSettings[i, platformIndex].settings == null) - m_TargetSettings[i, platformIndex].settings = CloneTargetSettings(m_TargetSettings[i, 0].settings); + //TODO: copy default to this platform ? or we don't care ? The AudioImporter doesn't care after all... } } } EditorGUILayout.Space(); - MultiTargetSettingState multiState = CalculateMultiTargetSettingState(platformIndex); - using (new EditorGUI.DisabledScope(!enableOverrideSettings)) + using (new EditorGUI.DisabledScope(overrideEnabled.hasMultipleDifferentValues || !overrideEnabled.boolValue)) { - OnTargetSettingsInspectorGUI(platformIndex, multiState); + OnTargetSettingsInspectorGUI(inspectorTargetSettings.FindPropertyRelative("settings")); } } @@ -758,6 +574,7 @@ internal override void OnHeaderControlsGUI() public override void OnInspectorGUI() { serializedObject.Update(); + extraDataSerializedObject.Update(); if (m_UseLegacyImporter.boolValue) { @@ -791,19 +608,12 @@ public override void OnInspectorGUI() } } + extraDataSerializedObject.ApplyModifiedProperties(); serializedObject.ApplyModifiedProperties(); ApplyRevertGUI(); } - public override bool HasModified() - { - if (base.HasModified()) - return true; - - return m_ModifiedTargetSettings; - } - protected override void Apply() { foreach (var t in targets) @@ -844,12 +654,6 @@ public override GUIContent GetPreviewTitle() return m_PreviewTitle; } - protected override void ResetValues() - { - base.ResetValues(); - ResetBackendValues(); - } - public override void OnPreviewSettings() { VideoClipImporter importer = (VideoClipImporter)target; diff --git a/Modules/AssetPipelineEditor/Public/AudioImporter.bindings.cs b/Modules/AssetPipelineEditor/Public/AudioImporter.bindings.cs index 68bb566676..24202dfb07 100644 --- a/Modules/AssetPipelineEditor/Public/AudioImporter.bindings.cs +++ b/Modules/AssetPipelineEditor/Public/AudioImporter.bindings.cs @@ -41,6 +41,7 @@ public enum AudioSampleRateSetting OverrideSampleRate = 2 } + [System.Serializable] public partial struct AudioImporterSampleSettings { public AudioClipLoadType loadType; diff --git a/Modules/AssetPipelineEditor/Public/ModelImporting/ModelImporter.bindings.cs b/Modules/AssetPipelineEditor/Public/ModelImporting/ModelImporter.bindings.cs index ee8d039da8..ee7ac5f9e7 100644 --- a/Modules/AssetPipelineEditor/Public/ModelImporting/ModelImporter.bindings.cs +++ b/Modules/AssetPipelineEditor/Public/ModelImporting/ModelImporter.bindings.cs @@ -88,6 +88,8 @@ public sealed partial class ModelImporterClipAnimation bool m_MaskNeedsUpdating; + long internalID; + public string takeName { get { return m_TakeName; } set { m_TakeName = value; } } public string name { get { return m_Name; } set { m_Name = value; } } public float firstFrame { get { return m_FirstFrame; } set { m_FirstFrame = value; } } @@ -444,6 +446,11 @@ public extern bool useFileUnits set; } + public extern float fileScale + { + get; + } + public extern bool useFileScale { get; diff --git a/Modules/AssetPipelineEditor/Public/VideoImporter.bindings.cs b/Modules/AssetPipelineEditor/Public/VideoImporter.bindings.cs index d247edf493..05544ca049 100644 --- a/Modules/AssetPipelineEditor/Public/VideoImporter.bindings.cs +++ b/Modules/AssetPipelineEditor/Public/VideoImporter.bindings.cs @@ -77,6 +77,7 @@ public enum VideoEncodeAspectRatio [NativeAsStruct] [StructLayout(LayoutKind.Sequential)] [NativeType(Header = "Modules/AssetPipelineEditor/Public/VideoClipImporter.h")] + [Serializable] public partial class VideoImporterTargetSettings { public bool enableTranscoding; diff --git a/Modules/Audio/Public/Managed/IHandle.cs b/Modules/Audio/Public/Managed/IHandle.cs new file mode 100644 index 0000000000..115b3fa1cc --- /dev/null +++ b/Modules/Audio/Public/Managed/IHandle.cs @@ -0,0 +1,18 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using System; +using System.Runtime.CompilerServices; +using UnityEngine.Bindings; + +[assembly: InternalsVisibleTo("UnityEngine.DSPGraphModule")] + +namespace Unity.Audio +{ + [VisibleToOtherModules] + internal interface IHandle : IValidatable, IEquatable + where HandleType : struct, IHandle + { + } +} diff --git a/Modules/Audio/Public/Managed/IValidatable.cs b/Modules/Audio/Public/Managed/IValidatable.cs new file mode 100644 index 0000000000..d1e0798378 --- /dev/null +++ b/Modules/Audio/Public/Managed/IValidatable.cs @@ -0,0 +1,14 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using UnityEngine.Bindings; + +namespace Unity.Audio +{ + [VisibleToOtherModules] + internal interface IValidatable + { + bool Valid { get; } + } +} diff --git a/Modules/Audio/Public/ScriptBindings/AudioClipExtensions.bindings.cs b/Modules/Audio/Public/ScriptBindings/AudioClipExtensions.bindings.cs index 1bc9b53edc..f342766bc1 100644 --- a/Modules/Audio/Public/ScriptBindings/AudioClipExtensions.bindings.cs +++ b/Modules/Audio/Public/ScriptBindings/AudioClipExtensions.bindings.cs @@ -3,9 +3,7 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License -using System; using UnityEngine.Bindings; -using UnityEngine; namespace UnityEngine.Experimental.Audio { @@ -15,8 +13,7 @@ namespace UnityEngine.Experimental.Audio internal static class AudioClipExtensionsInternal { [NativeMethod(IsFreeFunction = true, ThrowsException = true)] - public extern static uint Internal_CreateAudioClipSampleProvider( - AudioClip audioClip, ulong start, long end, bool loop, bool allowDrop); + public static extern uint Internal_CreateAudioClipSampleProvider(this AudioClip audioClip, ulong start, long end, bool loop, bool allowDrop); } } diff --git a/Modules/Audio/Public/ScriptBindings/AudioSampleProvider.bindings.cs b/Modules/Audio/Public/ScriptBindings/AudioSampleProvider.bindings.cs index 46989f3de0..c8d1ca0761 100644 --- a/Modules/Audio/Public/ScriptBindings/AudioSampleProvider.bindings.cs +++ b/Modules/Audio/Public/ScriptBindings/AudioSampleProvider.bindings.cs @@ -195,7 +195,7 @@ private void InvokeSampleFramesOverflow(int droppedSampleFrameCount) private static extern uint InternalCreateSampleProvider(ushort channelCount, uint sampleRate); [NativeMethod(IsThreadSafe = true)] - private static extern void InternalRemove(uint providerId); + internal static extern void InternalRemove(uint providerId); [NativeMethod(IsThreadSafe = true)] private static extern void InternalGetFormatInfo( @@ -211,7 +211,7 @@ private static extern void InternalSetScriptingPtr( uint providerId, AudioSampleProvider provider); [NativeMethod(IsThreadSafe = true)] - private static extern bool InternalIsValid(uint providerId); + internal static extern bool InternalIsValid(uint providerId); [NativeMethod(IsThreadSafe = true)] private static extern uint InternalGetMaxSampleFrameCount(uint providerId); diff --git a/Modules/Audio/Public/csas/ScriptBindings/ExposeDSPGraph.cs b/Modules/Audio/Public/ScriptBindings/ExposeDSPGraph.cs similarity index 100% rename from Modules/Audio/Public/csas/ScriptBindings/ExposeDSPGraph.cs rename to Modules/Audio/Public/ScriptBindings/ExposeDSPGraph.cs diff --git a/Modules/Audio/Public/csas/ScriptBindings/AudioHandle.bindings.cs b/Modules/Audio/Public/csas/ScriptBindings/AudioHandle.bindings.cs deleted file mode 100644 index 0cc809e432..0000000000 --- a/Modules/Audio/Public/csas/ScriptBindings/AudioHandle.bindings.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - - -using System; -using UnityEngine.Bindings; - -namespace Unity.Audio -{ - [NativeType(Header = "Modules/Audio/Public/csas/DSPGraphHandles.h")] - internal unsafe struct Handle : IEquatable - { - public System.IntPtr Ptr; - public System.Int32 Version; - - public bool Equals(Handle other) - { - return Ptr == other.Ptr && - Version == other.Version; - } - } -} - diff --git a/Modules/Audio/Public/csas/ScriptBindings/DSPGraph.bindings.cs b/Modules/Audio/Public/csas/ScriptBindings/DSPGraph.bindings.cs deleted file mode 100644 index d07ad33a44..0000000000 --- a/Modules/Audio/Public/csas/ScriptBindings/DSPGraph.bindings.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - - -using System; -using UnityEngine.Bindings; - -namespace Unity.Audio -{ - [NativeType(Header = "Modules/Audio/Public/csas/DSPGraph.bindings.h")] - internal struct DSPGraphInternal - { - [NativeMethod(IsFreeFunction = true, ThrowsException = true)] - public static extern void Internal_CreateDSPGraph(out Handle graph, int outputFormat, uint outputChannels, uint dspBufferSize, uint sampleRate); - - [NativeMethod(IsFreeFunction = true)] - public static extern void Internal_GetDefaultGraph(out Handle graph); - - [NativeMethod(IsFreeFunction = true, ThrowsException = true)] - public static extern void Internal_DisposeDSPGraph(ref Handle graph); - - [NativeMethod(IsFreeFunction = true, ThrowsException = true)] - public static extern void Internal_CreateDSPCommandBlock(ref Handle graph, ref Handle block); - - [NativeMethod(IsFreeFunction = true, ThrowsException = true)] - public static extern uint Internal_AddNodeEventHandler( - ref Handle graph, long eventTypeHashCode, object handler); - - [NativeMethod(IsFreeFunction = true, ThrowsException = true)] - public static extern bool Internal_RemoveNodeEventHandler(ref Handle graph, uint handlerId); - - [NativeMethod(IsFreeFunction = true, ThrowsException = true)] - public static extern void Internal_GetRootDSP(ref Handle graph, ref Handle root); - - [NativeMethod(IsFreeFunction = true, ThrowsException = true)] - public static extern ulong Internal_GetDSPClock(ref Handle graph); - - [NativeMethod(IsFreeFunction = true, ThrowsException = true)] - public static extern void Internal_BeginMix(ref Handle graph); - - [NativeMethod(IsFreeFunction = true, ThrowsException = true)] - public static extern unsafe void Internal_ReadMix(ref Handle graph, void* buffer, int length); - - [NativeMethod(IsFreeFunction = true, ThrowsException = true)] - public static extern unsafe void Internal_Update(ref Handle graph); - } -} - diff --git a/Modules/Audio/Public/csas/ScriptBindings/DSPSampleProvider.bindings.cs b/Modules/Audio/Public/csas/ScriptBindings/DSPSampleProvider.bindings.cs deleted file mode 100644 index 70a78e6438..0000000000 --- a/Modules/Audio/Public/csas/ScriptBindings/DSPSampleProvider.bindings.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - - -using System; -using UnityEngine.Bindings; - -namespace Unity.Audio -{ - [NativeType(Header = "Modules/Audio/Public/csas/DSPSampleProvider.bindings.h")] - internal partial struct DSPSampleProviderInternal - { - [NativeMethod(IsThreadSafe = true, IsFreeFunction = true, ThrowsException = true)] - public static extern unsafe int Internal_ReadUInt8FromSampleProvider( - void* provider, int format, void* buffer, int length); - - [NativeMethod(IsThreadSafe = true, IsFreeFunction = true, ThrowsException = true)] - public static extern unsafe int Internal_ReadSInt16FromSampleProvider( - void* provider, int format, void* buffer, int length); - - [NativeMethod(IsThreadSafe = true, IsFreeFunction = true, ThrowsException = true)] - public static extern unsafe int Internal_ReadFloatFromSampleProvider( - void* provider, void* buffer, int length); - - [NativeMethod(IsThreadSafe = true, IsFreeFunction = true, ThrowsException = true)] - public static extern unsafe ushort Internal_GetChannelCount(void* provider); - - [NativeMethod(IsThreadSafe = true, IsFreeFunction = true, ThrowsException = true)] - public static extern unsafe uint Internal_GetSampleRate(void* provider); - } -} - diff --git a/Modules/BuildReportingEditor/Managed/BuildReport.bindings.cs b/Modules/BuildReportingEditor/Managed/BuildReport.bindings.cs index 19be0e3f49..51f39c2419 100644 --- a/Modules/BuildReportingEditor/Managed/BuildReport.bindings.cs +++ b/Modules/BuildReportingEditor/Managed/BuildReport.bindings.cs @@ -49,7 +49,7 @@ public StrippingInfo strippingInfo [FreeFunction("BuildReporting::SummarizeErrors", HasExplicitThis = true)] internal extern string SummarizeErrors(); - internal extern void AddMessage(LogType messageType, string message); + internal extern void AddMessage(LogType messageType, string message, string exceptionType); internal extern int BeginBuildStep(string stepName); internal extern void ResumeBuildStep(int depth); diff --git a/Modules/DSPGraph/Public/ScriptBindings/AudioHandle.bindings.cs b/Modules/DSPGraph/Public/ScriptBindings/AudioHandle.bindings.cs new file mode 100644 index 0000000000..fc8317eeb6 --- /dev/null +++ b/Modules/DSPGraph/Public/ScriptBindings/AudioHandle.bindings.cs @@ -0,0 +1,99 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + + +using System; +using System.Runtime.InteropServices; +using UnityEngine.Bindings; +using Unity.Collections.LowLevel.Unsafe; + +namespace Unity.Audio +{ + [NativeType(Header = "Modules/DSPGraph/Public/DSPGraphHandles.h")] + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct Handle : IHandle + { + [NativeDisableUnsafePtrRestriction] + private IntPtr m_Node; + public int Version; + + public Node* AtomicNode + { + get { return (Node*)m_Node; } + set + { + if (value == null) + throw new ArgumentNullException(); + m_Node = (IntPtr)value; + Version = value->Version; + } + } + + public int Id + { + get { return Valid ? AtomicNode->Id : Node.InvalidId; } + set + { + if (value == Node.InvalidId) + throw new ArgumentException("Invalid ID"); + if (!Valid) + throw new InvalidOperationException("Handle is invalid or has been destroyed"); + if (AtomicNode->Id != Node.InvalidId) + throw new InvalidOperationException($"Trying to overwrite id on live node {AtomicNode->Id}"); + AtomicNode->Id = value; + } + } + + public Handle(Node* node) + { + if (node == null) + throw new ArgumentNullException(nameof(node)); + if (node->Id != Node.InvalidId) + throw new InvalidOperationException($"Reusing unflushed node {node->Id}"); + Version = node->Version; + this.m_Node = (IntPtr)node; + } + + public void FlushNode() + { + if (!Valid) + throw new InvalidOperationException("Attempting to flush invalid audio handle"); + AtomicNode->Id = Node.InvalidId; + ++AtomicNode->Version; + } + + public bool Equals(Handle other) + { + return m_Node == other.m_Node && Version == other.Version; + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is Handle && Equals((Handle)obj); + } + + public override int GetHashCode() + { + unchecked + { + return ((int)m_Node * 397) ^ Version; + } + } + + public bool Valid => m_Node != IntPtr.Zero && AtomicNode->Version == Version; + public bool Alive => Valid && AtomicNode->Id != Node.InvalidId; + + [StructLayout(LayoutKind.Sequential)] + internal struct Node + { + public long Next; + public int Id; + public int Version; + public int DidAllocate; + public const int InvalidId = -1; + } + } +} + diff --git a/Modules/DSPGraph/Public/ScriptBindings/AudioMemoryManager.bindings.cs b/Modules/DSPGraph/Public/ScriptBindings/AudioMemoryManager.bindings.cs new file mode 100644 index 0000000000..95873f68b3 --- /dev/null +++ b/Modules/DSPGraph/Public/ScriptBindings/AudioMemoryManager.bindings.cs @@ -0,0 +1,20 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + + +using UnityEngine.Bindings; + +namespace Unity.Audio +{ + [NativeType(Header = "Modules/DSPGraph/Public/AudioMemoryManager.bindings.h")] + internal struct AudioMemoryManager + { + [NativeMethod(IsFreeFunction = true, ThrowsException = false)] + public static extern unsafe void* Internal_AllocateAudioMemory(int size, int alignment); + + [NativeMethod(IsFreeFunction = true, ThrowsException = false)] + public static extern unsafe void Internal_FreeAudioMemory(void* memory); + } +} + diff --git a/Modules/DSPGraph/Public/ScriptBindings/AudioOutputHookManager.bindings.cs b/Modules/DSPGraph/Public/ScriptBindings/AudioOutputHookManager.bindings.cs new file mode 100644 index 0000000000..8d645e7e6f --- /dev/null +++ b/Modules/DSPGraph/Public/ScriptBindings/AudioOutputHookManager.bindings.cs @@ -0,0 +1,20 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + + +using UnityEngine.Bindings; + +namespace Unity.Audio +{ + [NativeType(Header = "Modules/DSPGraph/Public/AudioOutputHookManager.bindings.h")] + internal struct AudioOutputHookManager + { + [NativeMethod(IsFreeFunction = true, ThrowsException = true)] + public static extern unsafe void Internal_CreateAudioOutputHook(out Handle outputHook, void* jobReflectionData, void* jobData); + + [NativeMethod(IsFreeFunction = true, ThrowsException = true)] + public static extern unsafe void Internal_DisposeAudioOutputHook(ref Handle outputHook); + } +} + diff --git a/Modules/Audio/Public/csas/ScriptBindings/DSPCommandBlock.bindings.cs b/Modules/DSPGraph/Public/ScriptBindings/DSPCommandBlock.bindings.cs similarity index 91% rename from Modules/Audio/Public/csas/ScriptBindings/DSPCommandBlock.bindings.cs rename to Modules/DSPGraph/Public/ScriptBindings/DSPCommandBlock.bindings.cs index e4557648ca..bf9059f528 100644 --- a/Modules/Audio/Public/csas/ScriptBindings/DSPCommandBlock.bindings.cs +++ b/Modules/DSPGraph/Public/ScriptBindings/DSPCommandBlock.bindings.cs @@ -8,7 +8,8 @@ namespace Unity.Audio { - [NativeType(Header = "Modules/Audio/Public/csas/DSPCommandBlock.bindings.h")] + [NativeHeader("Modules/DSPGraph/Public/DSPSampleProvider.bindings.h")] + [NativeType(Header = "Modules/DSPGraph/Public/DSPCommandBlock.bindings.h")] internal struct DSPCommandBlockInternal { [NativeMethod(IsFreeFunction = true, ThrowsException = true)] @@ -61,16 +62,19 @@ public static extern void Internal_Disconnect(ref Handle graph, ref Handle block public static extern void Internal_AddOutletPort(ref Handle graph, ref Handle block, ref Handle node, int channelCount, int format); [NativeMethod(IsFreeFunction = true, ThrowsException = true)] - public static extern unsafe void Internal_SetSampleProvider(ref Handle graph, ref Handle block, ref Handle node, int item, int index, uint audioSampleProviderId); + public static extern unsafe void Internal_SetSampleProvider(ref Handle graph, ref Handle block, ref Handle node, int item, int index, uint audioSampleProviderId, bool destroyOnRemove); [NativeMethod(IsFreeFunction = true, ThrowsException = true)] - public static extern unsafe void Internal_InsertSampleProvider(ref Handle graph, ref Handle block, ref Handle node, int item, int index, uint audioSampleProviderId); + public static extern unsafe void Internal_InsertSampleProvider(ref Handle graph, ref Handle block, ref Handle node, int item, int index, uint audioSampleProviderId, bool destroyOnRemove); [NativeMethod(IsFreeFunction = true, ThrowsException = true)] public static extern unsafe void Internal_RemoveSampleProvider(ref Handle graph, ref Handle block, ref Handle node, int item, int index); [NativeMethod(IsFreeFunction = true, ThrowsException = true)] public static extern void Internal_Complete(ref Handle graph, ref Handle block); + + [NativeMethod(IsFreeFunction = true, ThrowsException = true)] + public static extern void Internal_Cancel(ref Handle graph, ref Handle block); } } diff --git a/Modules/DSPGraph/Public/ScriptBindings/DSPGraph.bindings.cs b/Modules/DSPGraph/Public/ScriptBindings/DSPGraph.bindings.cs new file mode 100644 index 0000000000..beab6440d7 --- /dev/null +++ b/Modules/DSPGraph/Public/ScriptBindings/DSPGraph.bindings.cs @@ -0,0 +1,86 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + + +using Unity.Jobs; +using UnityEngine.Bindings; +using System.Runtime.InteropServices; + +namespace Unity.Audio +{ + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct DSPGraphExecutionNode + { + public void* ReflectionData; + public void* JobStructData; + public void* JobData; + public void* ResourceContext; + public int FunctionIndex; + public int FenceIndex; + public int FenceCount; + } + + [NativeType(Header = "Modules/DSPGraph/Public/DSPGraph.bindings.h")] + internal struct DSPGraphInternal + { + [NativeMethod(IsFreeFunction = true, ThrowsException = true)] + public static extern void Internal_CreateDSPGraph(out Handle graph, int outputFormat, uint outputChannels, uint dspBufferSize, uint sampleRate); + + [NativeMethod(IsFreeFunction = true, ThrowsException = true)] + public static extern void Internal_DisposeDSPGraph(ref Handle graph); + + [NativeMethod(IsFreeFunction = true, ThrowsException = true)] + public static extern void Internal_CreateDSPCommandBlock(ref Handle graph, ref Handle block); + + [NativeMethod(IsFreeFunction = true, ThrowsException = true)] + public static extern uint Internal_AddNodeEventHandler( + ref Handle graph, long eventTypeHashCode, object handler); + + [NativeMethod(IsFreeFunction = true, ThrowsException = true)] + public static extern bool Internal_RemoveNodeEventHandler(ref Handle graph, uint handlerId); + + [NativeMethod(IsFreeFunction = true, ThrowsException = true)] + public static extern void Internal_GetRootDSP(ref Handle graph, ref Handle root); + + [NativeMethod(IsFreeFunction = true, ThrowsException = true)] + public static extern ulong Internal_GetDSPClock(ref Handle graph); + + [NativeMethod(IsFreeFunction = true, ThrowsException = true, IsThreadSafe = true)] + public static extern void Internal_BeginMix(ref Handle graph, int frameCount, int executionMode); + + [NativeMethod(IsFreeFunction = true, ThrowsException = true, IsThreadSafe = true)] + public static extern unsafe void Internal_ReadMix(ref Handle graph, void* buffer, int frameCount); + + [NativeMethod(IsFreeFunction = true, ThrowsException = true)] + public static extern unsafe void Internal_Update(ref Handle graph); + + [NativeMethod(IsFreeFunction = true, ThrowsException = true, IsThreadSafe = true)] + public static extern bool Internal_AssertMixerThread(ref Handle graph); + + [NativeMethod(IsFreeFunction = true, ThrowsException = true, IsThreadSafe = true)] + public static extern bool Internal_AssertMainThread(ref Handle graph); + + [NativeMethod(IsFreeFunction = true, ThrowsException = true, IsThreadSafe = true)] + public static extern Handle Internal_AllocateHandle(ref Handle graph); + + [NativeMethod(IsFreeFunction = true, ThrowsException = true, IsThreadSafe = true)] + public static extern unsafe void Internal_InitializeJob(void* jobStructData, void* jobReflectionData, void* resourceContext); + + [NativeMethod(IsFreeFunction = true, ThrowsException = true, IsThreadSafe = true)] + public static extern unsafe void Internal_ExecuteJob(void* jobStructData, void* jobReflectionData, void* jobData, void* resourceContext); + + [NativeMethod(IsFreeFunction = true, ThrowsException = true, IsThreadSafe = true)] + public static extern unsafe void Internal_ExecuteUpdateJob(void* updateStructMemory, void* updateReflectionData, void* jobStructMemory, void* jobReflectionData, void* resourceContext, ref Handle requestHandle, ref JobHandle fence); + + [NativeMethod(IsFreeFunction = true, ThrowsException = true, IsThreadSafe = true)] + public static extern unsafe void Internal_DisposeJob(void* jobStructData, void* jobReflectionData, void* resourceContext); + + [NativeMethod(IsFreeFunction = true, ThrowsException = true, IsThreadSafe = true)] + public static extern unsafe void Internal_ScheduleGraph(JobHandle inputDeps, void* nodes, int nodeCount, int* childTable, void* dependencies); + + [NativeMethod(IsFreeFunction = true, ThrowsException = true, IsThreadSafe = true)] + public static extern void Internal_SyncFenceNoWorkSteal(JobHandle handle); + } +} + diff --git a/Modules/Audio/Public/csas/ScriptBindings/DSPNodeUpdateRequest.bindings.cs b/Modules/DSPGraph/Public/ScriptBindings/DSPNodeUpdateRequest.bindings.cs similarity index 93% rename from Modules/Audio/Public/csas/ScriptBindings/DSPNodeUpdateRequest.bindings.cs rename to Modules/DSPGraph/Public/ScriptBindings/DSPNodeUpdateRequest.bindings.cs index 806171e5a8..0c927ff5be 100644 --- a/Modules/Audio/Public/csas/ScriptBindings/DSPNodeUpdateRequest.bindings.cs +++ b/Modules/DSPGraph/Public/ScriptBindings/DSPNodeUpdateRequest.bindings.cs @@ -9,7 +9,7 @@ namespace Unity.Audio { - [NativeType(Header = "Modules/Audio/Public/csas/DSPNodeUpdateRequest.bindings.h")] + [NativeType(Header = "Modules/DSPGraph/Public/DSPNodeUpdateRequest.bindings.h")] internal struct DSPNodeUpdateRequestHandleInternal { [NativeMethod(IsFreeFunction = true, ThrowsException = true)] diff --git a/Modules/DSPGraph/Public/ScriptBindings/DSPSampleProvider.bindings.cs b/Modules/DSPGraph/Public/ScriptBindings/DSPSampleProvider.bindings.cs new file mode 100644 index 0000000000..826e2d9655 --- /dev/null +++ b/Modules/DSPGraph/Public/ScriptBindings/DSPSampleProvider.bindings.cs @@ -0,0 +1,44 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + + +using UnityEngine.Bindings; + +namespace Unity.Audio +{ + [NativeType(Header = "Modules/DSPGraph/Public/DSPSampleProvider.bindings.h")] + internal partial struct DSPSampleProviderInternal + { + [NativeMethod(IsThreadSafe = true, IsFreeFunction = true, ThrowsException = true)] + public static extern unsafe int Internal_ReadUInt8FromSampleProvider(void* provider, int format, void* buffer, int length); + + [NativeMethod(IsThreadSafe = true, IsFreeFunction = true, ThrowsException = true)] + public static extern unsafe int Internal_ReadSInt16FromSampleProvider(void* provider, int format, void* buffer, int length); + + [NativeMethod(IsThreadSafe = true, IsFreeFunction = true, ThrowsException = true)] + public static extern unsafe int Internal_ReadFloatFromSampleProvider(void* provider, void* buffer, int length); + + [NativeMethod(IsThreadSafe = true, IsFreeFunction = true, ThrowsException = true)] + public static extern unsafe ushort Internal_GetChannelCount(void* provider); + + [NativeMethod(IsThreadSafe = true, IsFreeFunction = true, ThrowsException = true)] + public static extern unsafe uint Internal_GetSampleRate(void* provider); + + [NativeMethod(IsThreadSafe = true, IsFreeFunction = true, ThrowsException = true)] + public static extern unsafe int Internal_ReadUInt8FromSampleProviderById(uint providerId, int format, void* buffer, int length); + + [NativeMethod(IsThreadSafe = true, IsFreeFunction = true, ThrowsException = true)] + public static extern unsafe int Internal_ReadSInt16FromSampleProviderById(uint providerId, int format, void* buffer, int length); + + [NativeMethod(IsThreadSafe = true, IsFreeFunction = true, ThrowsException = true)] + public static extern unsafe int Internal_ReadFloatFromSampleProviderById(uint providerId, void* buffer, int length); + + [NativeMethod(IsThreadSafe = true, IsFreeFunction = true, ThrowsException = true)] + public static extern unsafe ushort Internal_GetChannelCountById(uint providerId); + + [NativeMethod(IsThreadSafe = true, IsFreeFunction = true, ThrowsException = true)] + public static extern unsafe uint Internal_GetSampleRateById(uint providerId); + } +} + diff --git a/Modules/Audio/Public/csas/ScriptBindings/ExecuteContext.bindings.cs b/Modules/DSPGraph/Public/ScriptBindings/ExecuteContext.bindings.cs similarity index 85% rename from Modules/Audio/Public/csas/ScriptBindings/ExecuteContext.bindings.cs rename to Modules/DSPGraph/Public/ScriptBindings/ExecuteContext.bindings.cs index b06e05de27..7c4a4e761b 100644 --- a/Modules/Audio/Public/csas/ScriptBindings/ExecuteContext.bindings.cs +++ b/Modules/DSPGraph/Public/ScriptBindings/ExecuteContext.bindings.cs @@ -8,7 +8,7 @@ namespace Unity.Audio { - [NativeType(Header = "Modules/Audio/Public/csas/ExecuteContext.bindings.h")] + [NativeType(Header = "Modules/DSPGraph/Public/ExecuteContext.bindings.h")] internal unsafe struct ExecuteContextInternal { [NativeMethod(IsThreadSafe = true, IsFreeFunction = true)] diff --git a/Modules/DSPGraph/Public/ScriptBindings/ExposeDSPGraph.cs b/Modules/DSPGraph/Public/ScriptBindings/ExposeDSPGraph.cs new file mode 100644 index 0000000000..a6a83b89de --- /dev/null +++ b/Modules/DSPGraph/Public/ScriptBindings/ExposeDSPGraph.cs @@ -0,0 +1,9 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + + +// Expose the internals to the DSPGraph assembly +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Unity.Audio.DSPGraph")] +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Unity.Audio.DSPGraph.Tests")] + diff --git a/Modules/GraphViewEditor/Elements/Blackboard/Blackboard.cs b/Modules/GraphViewEditor/Elements/Blackboard/Blackboard.cs index bb6496c8af..0069e75acd 100644 --- a/Modules/GraphViewEditor/Elements/Blackboard/Blackboard.cs +++ b/Modules/GraphViewEditor/Elements/Blackboard/Blackboard.cs @@ -136,6 +136,20 @@ public Blackboard() { e.StopPropagation(); }); + + // event interception to prevent GraphView manipulators from being triggered + // when working with the blackboard + + // prevent Zoomer manipulator + RegisterCallback(e => + { + e.StopPropagation(); + }); + // prevent ContentDragger manipulator + RegisterCallback(e => + { + e.StopPropagation(); + }); } } } diff --git a/Modules/GraphViewEditor/Elements/Scope.cs b/Modules/GraphViewEditor/Elements/Scope.cs index 315b34c611..049ba99777 100644 --- a/Modules/GraphViewEditor/Elements/Scope.cs +++ b/Modules/GraphViewEditor/Elements/Scope.cs @@ -255,6 +255,28 @@ void MarkChildrenDirtyRepaint(VisualElement parent) } } + void MarkBoundingBoxesDirty(VisualElement ve) + { + var parent = ve.hierarchy.parent; + while (parent != null && !parent.isBoundingBoxDirty) + { + parent.isBoundingBoxDirty = true; + parent = parent.hierarchy.parent; + } + + MarkChildrenBoundingBoxesDirty(ve); + } + + void MarkChildrenBoundingBoxesDirty(VisualElement parent) + { + parent.isBoundingBoxDirty = true; + + for (int i = 0; i < parent.hierarchy.childCount; ++i) + { + MarkChildrenBoundingBoxesDirty(parent.hierarchy[i]); + } + } + public void UpdateGeometryFromContent() { hasPendingGeometryUpdate = false; @@ -283,6 +305,8 @@ public void UpdateGeometryFromContent() // The number of actual children should be low given the Scope (and Group) nodes do not parent their child nodes. // This is mostly to fix things like the title element in the Group node. MarkChildrenDirtyRepaint(this); + // We also need to mark the actual children bounding boxes as dirty, since the element dimensions may have changed. + MarkBoundingBoxesDirty(this); if (m_ContainedElements.Count > 0) { diff --git a/Modules/GraphViewEditor/Manipulators/SelectionDropper.cs b/Modules/GraphViewEditor/Manipulators/SelectionDropper.cs index 8c37f5a314..8873dc3180 100644 --- a/Modules/GraphViewEditor/Manipulators/SelectionDropper.cs +++ b/Modules/GraphViewEditor/Manipulators/SelectionDropper.cs @@ -180,7 +180,7 @@ protected void OnMouseUp(MouseUpEvent e) { if (selectedElement != null && selectionContainer != null && !m_Dragging) { - if (selectedElement.IsSelected((VisualElement)selectionContainer) && !e.actionKey) + if (selectedElement.IsSelected((VisualElement)selectionContainer) && !e.actionKey && e.button == (int)activateButton) { // Reset to single selection selectionContainer.ClearSelection(); diff --git a/Modules/IMGUI/GUI.cs b/Modules/IMGUI/GUI.cs index 0f63813d2c..1dfa7dcf3c 100644 --- a/Modules/IMGUI/GUI.cs +++ b/Modules/IMGUI/GUI.cs @@ -1334,7 +1334,7 @@ public static void EndClip() GUIClip.Pop(); } - private static readonly UnityEngineInternal.GenericStack s_ScrollViewStates = new UnityEngineInternal.GenericStack(); + internal static UnityEngineInternal.GenericStack scrollViewStates { get; set; } = new UnityEngineInternal.GenericStack(); public static Vector2 BeginScrollView(Rect position, Vector2 scrollPosition, Rect viewRect) { @@ -1392,7 +1392,7 @@ internal static Vector2 BeginScrollView(Rect position, Vector2 scrollPosition, R state.visibleRect = state.viewRect = viewRect; state.visibleRect.width = position.width; state.visibleRect.height = position.height; - s_ScrollViewStates.Push(state); + scrollViewStates.Push(state); Rect clipRect = new Rect(position); switch (Event.current.type) @@ -1476,11 +1476,11 @@ public static void EndScrollView() public static void EndScrollView(bool handleScrollWheel) { GUIUtility.CheckOnGUI(); - ScrollViewState state = (ScrollViewState)s_ScrollViewStates.Peek(); + ScrollViewState state = (ScrollViewState)scrollViewStates.Peek(); GUIClip.Pop(); - s_ScrollViewStates.Pop(); + scrollViewStates.Pop(); // This is the mac way of handling things: if the mouse is over a scrollview, the scrollview gets the event. if (handleScrollWheel && Event.current.type == EventType.ScrollWheel && state.position.Contains(Event.current.mousePosition) @@ -1505,8 +1505,8 @@ public static void EndScrollView(bool handleScrollWheel) internal static ScrollViewState GetTopScrollView() { - if (s_ScrollViewStates.Count != 0) - return (ScrollViewState)s_ScrollViewStates.Peek(); + if (scrollViewStates.Count != 0) + return (ScrollViewState)scrollViewStates.Peek(); return null; } diff --git a/Modules/IMGUI/GUIUtility.cs b/Modules/IMGUI/GUIUtility.cs index 62439b35ca..ddfc4c3915 100644 --- a/Modules/IMGUI/GUIUtility.cs +++ b/Modules/IMGUI/GUIUtility.cs @@ -240,6 +240,7 @@ internal static void ResetGlobalState() GUI.skin = null; guiIsExiting = false; GUI.changed = false; + GUI.scrollViewStates.Clear(); } [VisibleToOtherModules("UnityEngine.UIElementsModule")] diff --git a/Modules/Input/Private/Input.cs b/Modules/Input/Private/Input.cs index 9f96518aca..43df555c32 100644 --- a/Modules/Input/Private/Input.cs +++ b/Modules/Input/Private/Input.cs @@ -4,19 +4,20 @@ using System; using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; using UnityEngine; using UnityEngine.Scripting; - +[assembly: InternalsVisibleTo("Unity.InputSystem")] namespace UnityEngineInternal.Input { using NativeBeforeUpdateCallback = System.Action; using NativeDeviceDiscoveredCallback = System.Action; using NativeShouldRunUpdateCallback = System.Func; - public unsafe delegate void NativeUpdateCallback(NativeInputUpdateType updateType, NativeInputEventBuffer* buffer); + internal unsafe delegate void NativeUpdateCallback(NativeInputUpdateType updateType, NativeInputEventBuffer* buffer); // C# doesn't support multi-character literals, so we do it by hand here... - public enum NativeInputEventType + internal enum NativeInputEventType { DeviceRemoved = 0x4452454D, DeviceConfigChanged = 0x44434647, @@ -28,7 +29,7 @@ public enum NativeInputEventType // We pass this as a struct to make it less painful to change the OnUpdate() API if need be. [StructLayout(LayoutKind.Explicit, Size = structSize, Pack = 1)] - public unsafe struct NativeInputEventBuffer + internal unsafe struct NativeInputEventBuffer { public const int structSize = 20; // NOTE: Keep this as the first field in the struct. This avoids alignment/packing issues @@ -40,7 +41,7 @@ public unsafe struct NativeInputEventBuffer } [StructLayout(LayoutKind.Explicit, Size = structSize, Pack = 1)] - public struct NativeInputEvent + internal struct NativeInputEvent { public const int structSize = 20; @@ -61,7 +62,7 @@ public NativeInputEvent(NativeInputEventType type, int sizeInBytes, int deviceId } [Flags] - public enum NativeInputUpdateType + internal enum NativeInputUpdateType { Dynamic = 1 << 0, Fixed = 1 << 1, @@ -71,11 +72,16 @@ public enum NativeInputUpdateType } - public partial class NativeInputSystem + internal partial class NativeInputSystem { + // This generates warnings that these are not used. They are used, but only by the input system package + // (which can access these via InternalsVisibleTo). But since that is not available during unity build time, + // and since these are marked as internal, we'd get the warning. So we suppress these. + #pragma warning disable 649 public static NativeUpdateCallback onUpdate; public static NativeBeforeUpdateCallback onBeforeUpdate; public static NativeShouldRunUpdateCallback onShouldRunUpdate; + #pragma warning restore 649 static NativeDeviceDiscoveredCallback s_OnDeviceDiscoveredCallback; public static NativeDeviceDiscoveredCallback onDeviceDiscovered @@ -128,13 +134,10 @@ internal static void NotifyDeviceDiscovered(int deviceId, string deviceDescripto } [RequiredByNativeCode] - internal static bool ShouldRunUpdate(NativeInputUpdateType updateType) + internal static void ShouldRunUpdate(NativeInputUpdateType updateType, out bool retval) { NativeShouldRunUpdateCallback callback = onShouldRunUpdate; - if (callback != null) - return callback(updateType); - - return false; + retval = callback != null ? callback(updateType) : false; } } } diff --git a/Modules/Input/Private/InputModule.bindings.cs b/Modules/Input/Private/InputModule.bindings.cs index 346bdd13e5..23e8f0a60a 100644 --- a/Modules/Input/Private/InputModule.bindings.cs +++ b/Modules/Input/Private/InputModule.bindings.cs @@ -13,7 +13,7 @@ namespace UnityEngineInternal.Input [NativeHeader("Modules/Input/Private/InputModuleBindings.h")] [NativeHeader("Modules/Input/Private/InputInternal.h")] [NativeConditional("ENABLE_NEW_INPUT_SYSTEM")] - public partial class NativeInputSystem + internal partial class NativeInputSystem { internal static extern bool hasDeviceDiscoveredCallback { set; } diff --git a/Modules/PackageManager/Editor/Managed/EntitlementsInfo.cs b/Modules/PackageManager/Editor/Managed/EntitlementsInfo.cs deleted file mode 100644 index d10c832411..0000000000 --- a/Modules/PackageManager/Editor/Managed/EntitlementsInfo.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using System.Runtime.InteropServices; -using UnityEngine; -using UnityEngine.Bindings; -using RequiredByNativeCodeAttribute = UnityEngine.Scripting.RequiredByNativeCodeAttribute; - -namespace UnityEditor.PackageManager -{ - [Serializable] - [StructLayout(LayoutKind.Sequential)] - [RequiredByNativeCode] - [NativeAsStruct] - internal class EntitlementsInfo - { - [SerializeField] - [NativeName("isAllowed")] - private bool m_IsAllowed; - - public bool isAllowed { get { return m_IsAllowed; } } - } -} diff --git a/Modules/PackageManager/Editor/Managed/PackageInfo.cs b/Modules/PackageManager/Editor/Managed/PackageInfo.cs index baa3a14e36..5e8544a5e9 100644 --- a/Modules/PackageManager/Editor/Managed/PackageInfo.cs +++ b/Modules/PackageManager/Editor/Managed/PackageInfo.cs @@ -105,10 +105,6 @@ public sealed partial class PackageInfo [NativeName("hideInEditor")] private bool m_HideInEditor; - [SerializeField] - [NativeName("entitlements")] - private EntitlementsInfo m_Entitlements = new EntitlementsInfo(); - [SerializeField] [NativeName("datePublishedTicks")] private long m_DatePublishedTicks; @@ -134,7 +130,6 @@ internal PackageInfo() {} public string[] keywords { get { return m_Keywords; } } public AuthorInfo author { get { return m_Author; } } internal bool hideInEditor { get { return m_HideInEditor; } } - internal EntitlementsInfo entitlements { get { return m_Entitlements; } } public RegistryInfo registry { diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/PackageCollection.cs b/Modules/PackageManagerUI/Editor/Services/Packages/PackageCollection.cs index 20a3c3ddee..474b0755d7 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/PackageCollection.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/PackageCollection.cs @@ -369,6 +369,9 @@ private void RebuildPackageDictionary() // Consolidate with latest fetched package infos foreach (var p in allPackageInfos) { + var search = searchPackages.FirstOrDefault(packageInfo => p.PackageId == packageInfo.PackageId); + if (search != null) p.IsDiscoverable = search.IsDiscoverable; + if (p.HasFullFetch) continue; var latestInfo = GetLatestInfoInCache(p.PackageId); @@ -397,8 +400,6 @@ private void RebuildPackageDictionary() // Send a request for latest info foreach (var p in outdatedDisplayPackages) FetchLatestPackageInfo(p, true); - - MarkDependentModulesAsInstalled(); } private void RebuildDependenciesDictionnary() @@ -455,34 +456,6 @@ private void RebuildDependenciesDictionnary() } } - /// - /// We need no mark modules that are a dependency of any package/module as installed. - /// This is how the module system currently behaves, so the UI needs to match this. - /// - private void MarkDependentModulesAsInstalled() - { - // Reset previous installed state - foreach (var packageInfo in CompletePackageInfosList.Where(p => p.IsBuiltIn)) - packageInfo.IsInstalledByDependency = false; - - // Set dependent installed state - var installedPackages = LatestListPackages.Where(p => p.IsInstalled); - foreach (var package in installedPackages) - MarkModulesAsInstalled(package.DependentModules); - } - - private void MarkModulesAsInstalled(IEnumerable modules) - { - foreach (var module in modules) - { - var latestInfo = CompletePackageInfosList.FirstOrDefault(p => p.PackageId == PackageInfo.FormatPackageId(module)); - if (latestInfo == null) - Debug.LogWarning("Module does not have package info: " + module.name); - if (latestInfo != null && !latestInfo.IsInstalled) - latestInfo.IsInstalledByDependency = true; - } - } - public IEnumerable GetDependents(PackageInfo packageInfo) { var installedRoots = LatestListPackages.Where(p => p.IsInstalled && p.Info.isDirectDependency); diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/PackageInfo.cs b/Modules/PackageManagerUI/Editor/Services/Packages/PackageInfo.cs index 227da0a843..01c6fefa44 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/PackageInfo.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/PackageInfo.cs @@ -27,8 +27,7 @@ internal class PackageInfo : IEquatable, ISerializationCallbackRece public string Description; public string Category; public PackageState State; - public bool IsInstalledByDependency; - public bool IsInstalledByUpm; + public bool IsInstalledByDependency => IsInstalled && (!Info?.isDirectDependency ?? false); public bool IsLatest; public string Group; public string Type; @@ -46,11 +45,7 @@ internal class PackageInfo : IEquatable, ISerializationCallbackRece public PackageManager.PackageInfo Info; - public bool IsInstalled - { - get { return IsInstalledByUpm || IsInstalledByDependency; } - set { IsInstalledByUpm = value; } - } + public bool IsInstalled; public static string ModulePrefix { get { return string.Format("{0}modules.", UnityPrefix); } } public static string UnityPrefix { get { return "com.unity."; } } diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/PackageSample.cs b/Modules/PackageManagerUI/Editor/Services/Packages/PackageSample.cs index 43bbb786e3..8b390b7d2e 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/PackageSample.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/PackageSample.cs @@ -31,9 +31,10 @@ internal static List LoadSamplesFromPackageJson(string package var packageJsonPath = System.IO.Path.Combine(packagePath, "package.json"); if (!File.Exists(packageJsonPath)) throw new FileNotFoundException(packageJsonPath); + var packageJsonText = File.ReadAllText(packageJsonPath); var packageJson = JsonUtility.FromJson(packageJsonText); - return packageJson.samples; + return packageJson != null ? packageJson.samples : new List(); } } diff --git a/Modules/PackageManagerUI/Editor/UI/PackageDetails.cs b/Modules/PackageManagerUI/Editor/UI/PackageDetails.cs index b5dbab4894..c42c4f1d10 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageDetails.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageDetails.cs @@ -591,12 +591,14 @@ private string GetPackageDashList(IEnumerable packageInfos, int max /// /// Get the full dependent message string /// - private string GetDependentMessage(IEnumerable roots, int maxListCount = MaxDependentList) + private string GetDependentMessage(PackageInfo packageInfo, IEnumerable roots, int maxListCount = MaxDependentList) { var dependentPackages = roots.Where(p => !p.IsBuiltIn).ToList(); var dependentModules = roots.Where(p => p.IsBuiltIn).ToList(); - var message = string.Format("{0}{1}:\n\n", "This built-in package is a dependency of the following ", dependentPackages.Any() ? "packages" : "built-in packages"); + var packageType = packageInfo.IsBuiltIn ? "built-in package" : "package"; + var prefix = $"This {packageType} is a dependency of the following "; + var message = string.Format("{0}{1}:\n\n", prefix, dependentPackages.Any() ? "packages" : "built-in packages"); if (dependentPackages.Any()) message += GetPackageDashList(dependentPackages, maxListCount); @@ -608,37 +610,48 @@ private string GetDependentMessage(IEnumerable roots, int maxListCo if (roots.Count() > maxListCount) message += "\n\n ... and more (see console for details) ..."; - message += "\n\nYou will need to remove or disable them before being able to disable this built-in package."; + var actionType = packageInfo.IsBuiltIn ? "disable" : "remove"; + message += $"\n\nYou will need to remove or disable them before being able to {actionType} this {packageType}."; return message; } private void RemoveClick() { - if (DisplayPackage.IsBuiltIn) + var roots = Collection.GetDependents(DisplayPackage).ToList(); + // Only show this message on a package if it is installed by dependency only. This allows it to still be removed from the installed list. + var showDialog = roots.Any() && !(!DisplayPackage.IsBuiltIn && DisplayPackage.IsDirectDependency); + if (showDialog) { - var roots = Collection.GetDependents(DisplayPackage).ToList(); - if (roots.Any()) - { - if (roots.Count > MaxDependentList) - Debug.Log(GetDependentMessage(roots, int.MaxValue)); + if (roots.Count > MaxDependentList) + Debug.Log(GetDependentMessage(DisplayPackage, roots, int.MaxValue)); - var message = GetDependentMessage(roots); - EditorUtility.DisplayDialog("Cannot Disable Built-In Package", message, "Ok"); + var message = GetDependentMessage(DisplayPackage, roots); + var title = DisplayPackage.IsBuiltIn ? "Cannot disable built-in package" : "Cannot remove dependent package"; + EditorUtility.DisplayDialog(title, message, "Ok"); - return; - } + return; } - var result = 1; // Cancel - if (!PackageManagerPrefs.SkipRemoveConfirmation) + var result = 0; + if (DisplayPackage.IsBuiltIn) { - result = EditorUtility.DisplayDialogComplex("Removing Package", - "Are you sure you wanted to remove this package?", - "Remove", "Cancel", "Remove and do not ask again"); + if (!PackageManagerPrefs.SkipDisableConfirmation) + { + result = EditorUtility.DisplayDialogComplex("Disable Built-In Package", + "Are you sure you want to disable this built-in package?", + "Disable", "Cancel", "Disable and don't ask again"); + } } else - result = 0; + { + if (!PackageManagerPrefs.SkipRemoveConfirmation) + { + result = EditorUtility.DisplayDialogComplex("Removing Package", + "Are you sure you want to remove this package?", + "Remove", "Cancel", "Remove and don't ask again"); + } + } // Cancel if (result == 1) @@ -646,7 +659,12 @@ private void RemoveClick() // Do not ask again if (result == 2) - PackageManagerPrefs.SkipRemoveConfirmation = true; + { + if (DisplayPackage.IsBuiltIn) + PackageManagerPrefs.SkipDisableConfirmation = true; + else + PackageManagerPrefs.SkipRemoveConfirmation = true; + } // Remove DetailError.ClearError(); diff --git a/Modules/PackageManagerUI/Editor/UI/PackageList.cs b/Modules/PackageManagerUI/Editor/UI/PackageList.cs index d4e8b8bed0..8c4ef7f338 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageList.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageList.cs @@ -233,14 +233,24 @@ private bool SelectBy(int delta) if (selection != null) { var index = list.IndexOf(selection); - var nextIndex = index + delta; - if (nextIndex >= list.Count) - return false; - if (nextIndex < 0) - return false; + var direction = Math.Sign(delta); + delta = Math.Abs(delta); + var nextIndex = index; + var numVisibleElements = 0; + IPackageSelection nextElement = null; + while (numVisibleElements < delta) + { + nextIndex += direction; + if (nextIndex >= list.Count) + return false; + if (nextIndex < 0) + return false; + nextElement = list.ElementAt(nextIndex); + if (UIUtils.IsElementVisible(nextElement.Element)) + ++numVisibleElements; + } - var nextElement = list.ElementAt(nextIndex); Selection.SetSelection(nextElement.TargetVersion); foreach (var scrollView in UIUtils.GetParentsOfType(nextElement.Element)) diff --git a/Modules/PackageManagerUI/Editor/UI/PackageManagerPrefs.cs b/Modules/PackageManagerUI/Editor/UI/PackageManagerPrefs.cs index 99a035b863..f1b00296f9 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageManagerPrefs.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageManagerPrefs.cs @@ -10,6 +10,7 @@ namespace UnityEditor.PackageManager.UI internal static class PackageManagerPrefs { private const string kSkipRemoveConfirmationPrefs = "PackageManager.SkipRemoveConfirmation"; + private const string kSkipDisableConfirmationPrefs = "PackageManager.SkipDisableConfirmation"; private const string kShowPackageDependenciesPrefs = "PackageManager.ShowPackageDependencies"; private const string kShowPreviewPackagesPrefKeyPrefix = "PackageManager.ShowPreviewPackages_"; private const string kShowPreviewPackagesWarningPrefs = "PackageManager.ShowPreviewPackagesWarning"; @@ -27,6 +28,12 @@ public static bool SkipRemoveConfirmation set { EditorPrefs.SetBool(kSkipRemoveConfirmationPrefs, value); } } + public static bool SkipDisableConfirmation + { + get { return EditorPrefs.GetBool(kSkipDisableConfirmationPrefs, false); } + set { EditorPrefs.SetBool(kSkipDisableConfirmationPrefs, value); } + } + public static bool ShowPackageDependencies { get { return EditorPrefs.GetBool(kShowPackageDependenciesPrefs, false); } diff --git a/Modules/PackageManagerUI/Editor/UI/PackageSearchToolbar.cs b/Modules/PackageManagerUI/Editor/UI/PackageSearchToolbar.cs index dabfbcd817..0edc95d57d 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageSearchToolbar.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageSearchToolbar.cs @@ -56,12 +56,14 @@ public void SetSearchText(string text) showingPlaceHolder = true; SearchTextField.value = kPlaceHolder; SearchTextField.AddToClassList("placeholder"); + SearchCancelButton.RemoveFromClassList("on"); } else { showingPlaceHolder = false; SearchTextField.value = searchText; SearchTextField.RemoveFromClassList("placeholder"); + SearchCancelButton.AddToClassList("on"); } } diff --git a/Modules/ParticleSystem/Managed/ParticleSystemStructs.cs b/Modules/ParticleSystem/Managed/ParticleSystemStructs.cs index b524bfc0ef..44629aafc1 100644 --- a/Modules/ParticleSystem/Managed/ParticleSystemStructs.cs +++ b/Modules/ParticleSystem/Managed/ParticleSystemStructs.cs @@ -238,6 +238,30 @@ private enum Flags [StructLayout(LayoutKind.Sequential)] public partial struct EmitParams { + public Particle particle + { + get + { + return m_Particle; + } + + set + { + m_Particle = value; + + m_PositionSet = true; + m_VelocitySet = true; + m_AxisOfRotationSet = true; + m_RotationSet = true; + m_AngularVelocitySet = true; + m_StartSizeSet = true; + m_StartColorSet = true; + m_RandomSeedSet = true; + m_StartLifetimeSet = true; + m_MeshIndexSet = true; + } + } + public Vector3 position { get { return m_Particle.position; } set { m_Particle.position = value; m_PositionSet = true; } } public bool applyShapeToPosition { get { return m_ApplyShapeToPosition; } set { m_ApplyShapeToPosition = value; } } public Vector3 velocity { get { return m_Particle.velocity; } set { m_Particle.velocity = value; m_VelocitySet = true; } } diff --git a/Modules/ParticleSystem/ScriptBindings/ParticleSystem.bindings.cs b/Modules/ParticleSystem/ScriptBindings/ParticleSystem.bindings.cs index c48c6a1df9..ed481bf42d 100644 --- a/Modules/ParticleSystem/ScriptBindings/ParticleSystem.bindings.cs +++ b/Modules/ParticleSystem/ScriptBindings/ParticleSystem.bindings.cs @@ -209,22 +209,22 @@ public partial struct ParticleCollisionEvent internal class ParticleSystemExtensionsImpl { [FreeFunction(Name = "ParticleSystemScriptBindings::GetSafeCollisionEventSize")] - extern internal static int GetSafeCollisionEventSize(ParticleSystem ps); + extern internal static int GetSafeCollisionEventSize([NotNull] ParticleSystem ps); [FreeFunction(Name = "ParticleSystemScriptBindings::GetCollisionEventsDeprecated")] - extern internal static int GetCollisionEventsDeprecated(ParticleSystem ps, GameObject go, [Out] ParticleCollisionEvent[] collisionEvents); + extern internal static int GetCollisionEventsDeprecated([NotNull] ParticleSystem ps, GameObject go, [Out] ParticleCollisionEvent[] collisionEvents); [FreeFunction(Name = "ParticleSystemScriptBindings::GetSafeTriggerParticlesSize")] - extern internal static int GetSafeTriggerParticlesSize(ParticleSystem ps, int type); + extern internal static int GetSafeTriggerParticlesSize([NotNull] ParticleSystem ps, int type); [FreeFunction(Name = "ParticleSystemScriptBindings::GetCollisionEvents")] - extern internal static int GetCollisionEvents(ParticleSystem ps, [NotNull] GameObject go, [NotNull] List collisionEvents); + extern internal static int GetCollisionEvents([NotNull] ParticleSystem ps, [NotNull] GameObject go, [NotNull] List collisionEvents); [FreeFunction(Name = "ParticleSystemScriptBindings::GetTriggerParticles")] - extern internal static int GetTriggerParticles(ParticleSystem ps, int type, [NotNull] List particles); + extern internal static int GetTriggerParticles([NotNull] ParticleSystem ps, int type, [NotNull] List particles); [FreeFunction(Name = "ParticleSystemScriptBindings::SetTriggerParticles")] - extern internal static void SetTriggerParticles(ParticleSystem ps, int type, [NotNull] List particles, int offset, int count); + extern internal static void SetTriggerParticles([NotNull] ParticleSystem ps, int type, [NotNull] List particles, int offset, int count); } public static partial class ParticlePhysicsExtensions diff --git a/Modules/ParticleSystemEditor/ParticleEffectUI.cs b/Modules/ParticleSystemEditor/ParticleEffectUI.cs index 427591c8a6..8aa9fe1b30 100644 --- a/Modules/ParticleSystemEditor/ParticleEffectUI.cs +++ b/Modules/ParticleSystemEditor/ParticleEffectUI.cs @@ -86,6 +86,7 @@ static Event CreateCommandEvent(string commandName) static Event s_PlayEvent = CreateCommandEvent("Play"); static Event s_StopEvent = CreateCommandEvent("Stop"); + static Event s_RestartEvent = CreateCommandEvent("Restart"); static Event s_ForwardBeginEvent = CreateCommandEvent("ForwardBegin"); static Event s_ForwardEndEvent = CreateCommandEvent("ForwardEnd"); static Event s_ReverseBeginEvent = CreateCommandEvent("ReverseBegin"); @@ -114,6 +115,12 @@ static void StopShortcut(ShortcutArguments args) DispatchShortcutEvent(s_StopEvent); } + [Shortcut("ParticleSystem/Restart", typeof(ParticleSystemInspector.ShortcutContext), KeyCode.Slash)] + static void RestartShortcut(ShortcutArguments args) + { + DispatchShortcutEvent(s_RestartEvent); + } + [FormerlyPrefKeyAs("ParticleSystem/Forward", "m")] [ClutchShortcut("ParticleSystem/Forward", typeof(ParticleSystemInspector.ShortcutContext), KeyCode.M)] static void ForwardShortcut(ShortcutArguments args) @@ -668,6 +675,12 @@ private void HandleKeyboardShortcuts() Stop(); evt.Use(); } + else if (evt.commandName == s_RestartEvent.commandName) + { + Stop(); + Play(); + evt.Use(); + } else if (evt.commandName == s_ForwardBeginEvent.commandName) { m_ScrubForward = true; diff --git a/Modules/ParticleSystemEditor/ParticleSystemModules/CollisionModuleUI.cs b/Modules/ParticleSystemEditor/ParticleSystemModules/CollisionModuleUI.cs index b6480ba960..c4e2589dc4 100644 --- a/Modules/ParticleSystemEditor/ParticleSystemModules/CollisionModuleUI.cs +++ b/Modules/ParticleSystemEditor/ParticleSystemModules/CollisionModuleUI.cs @@ -70,7 +70,7 @@ class Texts public GUIContent collidesWithDynamic = EditorGUIUtility.TrTextContent("Enable Dynamic Colliders", "Should particles collide with dynamic objects?"); public GUIContent maxCollisionShapes = EditorGUIUtility.TrTextContent("Max Collision Shapes", "How many collision shapes can be considered for particle collisions. Excess shapes will be ignored. Terrains take priority."); public GUIContent quality = EditorGUIUtility.TrTextContent("Collision Quality", "Quality of world collisions. Medium and low quality are approximate and may leak particles."); - public GUIContent voxelSize = EditorGUIUtility.TrTextContent("Voxel Size", "Size of voxels in the collision cache. Smaller values improve accuracy, but require higher memory usage and are less efficient."); + public GUIContent voxelSize = EditorGUIUtility.TrTextContent("Voxel Size", "Size of voxels in the collision cache. Smaller values improve accuracy but require higher memory usage and are less efficient."); public GUIContent collisionMessages = EditorGUIUtility.TrTextContent("Send Collision Messages", "Send collision callback messages."); public GUIContent collisionType = EditorGUIUtility.TrTextContent("Type", "Collide with a list of Planes, or the Physics World."); public GUIContent collisionMode = EditorGUIUtility.TrTextContent("Mode", "Use 3D Physics or 2D Physics."); diff --git a/Modules/ParticleSystemEditor/ParticleSystemModules/InitialModuleUI.cs b/Modules/ParticleSystemEditor/ParticleSystemModules/InitialModuleUI.cs index 848208a6ab..ea0cc071e4 100644 --- a/Modules/ParticleSystemEditor/ParticleSystemModules/InitialModuleUI.cs +++ b/Modules/ParticleSystemEditor/ParticleSystemModules/InitialModuleUI.cs @@ -47,7 +47,7 @@ class Texts { public GUIContent duration = EditorGUIUtility.TrTextContent("Duration", "The length of time the Particle System is emitting particles. If the system is looping, this indicates the length of one cycle."); public GUIContent looping = EditorGUIUtility.TrTextContent("Looping", "If true, the emission cycle will repeat after the duration."); - public GUIContent prewarm = EditorGUIUtility.TrTextContent("Prewarm", "When played a prewarmed system will be in a state as if it had emitted one loop cycle. Can only be used if the system is looping."); + public GUIContent prewarm = EditorGUIUtility.TrTextContent("Prewarm", "When played, a prewarmed system will be in a state as if it had emitted one loop cycle. Can only be used if the system is looping."); public GUIContent startDelay = EditorGUIUtility.TrTextContent("Start Delay", "Delay in seconds that this Particle System will wait before emitting particles. Cannot be used together with a prewarmed looping system."); public GUIContent maxParticles = EditorGUIUtility.TrTextContent("Max Particles", "The number of particles in the system will be limited by this number. Emission will be temporarily halted if this is reached."); public GUIContent lifetime = EditorGUIUtility.TrTextContent("Start Lifetime", "Start lifetime in seconds, particle will die when its lifetime reaches 0."); @@ -69,7 +69,7 @@ class Texts public GUIContent randomSeed = EditorGUIUtility.TrTextContent("Random Seed", "Randomize the look of the Particle System. Using the same seed will make the Particle System play identically each time. After changing this value, restart the Particle System to see the changes, or check the Resimulate box."); public GUIContent emitterVelocity = EditorGUIUtility.TrTextContent("Emitter Velocity", "When the Particle System is moving, should we use its Transform, or Rigidbody Component, to calculate its velocity?"); public GUIContent stopAction = EditorGUIUtility.TrTextContent("Stop Action", "When the Particle System is stopped and all particles have died, should the GameObject automatically disable/destroy itself?"); - public GUIContent cullingMode = EditorGUIUtility.TrTextContent("Culling Mode", "Choose whether to continue simulating the Particle System when offscreen. Catch-up mode pauses offscreen simulations, but performs a large simulation step when they become visible, giving the appearance that they were never paused. Automatic uses Pause mode for looping systems, and AlwaysSimulate if not looping."); + public GUIContent cullingMode = EditorGUIUtility.TrTextContent("Culling Mode", "Choose whether to continue simulating the Particle System when offscreen. Catch-up mode pauses offscreen simulations but performs a large simulation step when they become visible, giving the appearance that they were never paused. Automatic uses Pause mode for looping systems, and AlwaysSimulate if not looping."); public GUIContent ringBufferMode = EditorGUIUtility.TrTextContent("Ring Buffer Mode", "Rather than dying when their lifetime has elapsed, particles will remain alive until the Max Particles buffer is full, at which point new particles will replace the oldest."); public GUIContent ringBufferLoopRange = EditorGUIUtility.TrTextContent("Loop Range", "Particle lifetimes may loop between a fade-in and fade-out time, in order to use curves for the entire time they are alive. Values are in the 0-1 range."); public GUIContent x = EditorGUIUtility.TextContent("X"); diff --git a/Modules/ParticleSystemEditor/ParticleSystemModules/RendererModuleUI.cs b/Modules/ParticleSystemEditor/ParticleSystemModules/RendererModuleUI.cs index c5fcb5eb6b..3610b3ec08 100644 --- a/Modules/ParticleSystemEditor/ParticleSystemModules/RendererModuleUI.cs +++ b/Modules/ParticleSystemEditor/ParticleSystemModules/RendererModuleUI.cs @@ -87,6 +87,7 @@ class Texts public GUIContent speedScale = EditorGUIUtility.TrTextContent("Speed Scale", "Defines the length of the particle compared to its speed."); public GUIContent lengthScale = EditorGUIUtility.TrTextContent("Length Scale", "Defines the length of the particle compared to its width."); public GUIContent sortingFudge = EditorGUIUtility.TrTextContent("Sorting Fudge", "Lower the number and most likely these particles will appear in front of other transparent objects, including other particles."); + public GUIContent sortingFudgeDisabledDueToSortingGroup = EditorGUIUtility.TrTextContent("Sorting Fudge", "This is disabled as the Sorting Group component handles the sorting for this Renderer."); public GUIContent sortMode = EditorGUIUtility.TrTextContent("Sort Mode", "The draw order of particles can be sorted by distance, oldest in front, or youngest in front."); public GUIContent rotation = EditorGUIUtility.TrTextContent("Rotation", "Set whether the rotation of the particles is defined in Screen or World space."); public GUIContent castShadows = EditorGUIUtility.TrTextContent("Cast Shadows", "Only opaque materials cast shadows"); @@ -245,6 +246,8 @@ protected override void Init() override public void OnInspectorGUI(InitialModuleUI initial) { + var renderer = serializedObject.targetObject as Renderer; + EditorGUI.BeginChangeCheck(); RenderMode renderMode = (RenderMode)GUIPopup(s_Texts.renderMode, m_RenderMode, s_Texts.particleTypes); bool renderModeChanged = EditorGUI.EndChangeCheck(); @@ -290,7 +293,15 @@ override public void OnInspectorGUI(InitialModuleUI initial) if (!m_RenderMode.hasMultipleDifferentValues) { GUIPopup(s_Texts.sortMode, m_SortMode, s_Texts.sortTypes); - GUIFloat(s_Texts.sortingFudge, m_SortingFudge); + if (renderer != null && SortingGroup.invalidSortingGroupID != renderer.sortingGroupID) + { + using (new EditorGUI.DisabledScope(true)) + GUIFloat(s_Texts.sortingFudgeDisabledDueToSortingGroup, m_SortingFudge); + } + else + { + GUIFloat(s_Texts.sortingFudge, m_SortingFudge); + } if (renderMode != RenderMode.Mesh) { @@ -379,7 +390,7 @@ override public void OnInspectorGUI(InitialModuleUI initial) var renderersArray = renderers.ToArray(); m_Probes.OnGUI(renderersArray, renderers.FirstOrDefault(), true); - RendererEditorBase.DrawRenderingLayer(m_RenderingLayerMask, serializedObject.targetObject as Renderer, renderersArray, true); + RendererEditorBase.DrawRenderingLayer(m_RenderingLayerMask, renderer, renderersArray, true); RendererEditorBase.DrawRendererPriority(m_RendererPriority, true); } diff --git a/Modules/ParticleSystemEditor/ParticleSystemModules/TriggerModuleUI.cs b/Modules/ParticleSystemEditor/ParticleSystemModules/TriggerModuleUI.cs index 40c700fac1..4f30706c16 100644 --- a/Modules/ParticleSystemEditor/ParticleSystemModules/TriggerModuleUI.cs +++ b/Modules/ParticleSystemEditor/ParticleSystemModules/TriggerModuleUI.cs @@ -30,8 +30,8 @@ class Texts public GUIContent createCollisionShape = EditorGUIUtility.TrTextContent("", "Create a GameObject containing a sphere collider and assigns it to the list."); public GUIContent inside = EditorGUIUtility.TrTextContent("Inside", "What to do for particles that are inside the collision volume."); public GUIContent outside = EditorGUIUtility.TrTextContent("Outside", "What to do for particles that are outside the collision volume."); - public GUIContent enter = EditorGUIUtility.TrTextContent("Enter", "Triggered once when particles enter the collison volume."); - public GUIContent exit = EditorGUIUtility.TrTextContent("Exit", "Triggered once when particles leave the collison volume."); + public GUIContent enter = EditorGUIUtility.TrTextContent("Enter", "Triggered once when particles enter the collision volume."); + public GUIContent exit = EditorGUIUtility.TrTextContent("Exit", "Triggered once when particles leave the collision volume."); public GUIContent radiusScale = EditorGUIUtility.TrTextContent("Radius Scale", "Scale particle bounds by this amount to get more precise collisions."); public GUIContent visualizeBounds = EditorGUIUtility.TrTextContent("Visualize Bounds", "Render the collision bounds of the particles."); diff --git a/Modules/ParticleSystemEditor/ParticleSystemModules/UVModuleUI.cs b/Modules/ParticleSystemEditor/ParticleSystemModules/UVModuleUI.cs index e003212301..87f44b0f67 100644 --- a/Modules/ParticleSystemEditor/ParticleSystemModules/UVModuleUI.cs +++ b/Modules/ParticleSystemEditor/ParticleSystemModules/UVModuleUI.cs @@ -29,7 +29,7 @@ class Texts public GUIContent mode = EditorGUIUtility.TrTextContent("Mode", "Animation frames can either be specified on a regular grid texture, or as a list of Sprites."); public GUIContent timeMode = EditorGUIUtility.TrTextContent("Time Mode", "Play frames either based on the lifetime of the particle, the speed of the particle, or at a constant FPS, regardless of particle lifetime."); public GUIContent fps = EditorGUIUtility.TrTextContent("FPS", "Specify the Frames Per Second of the animation."); - public GUIContent frameOverTime = EditorGUIUtility.TrTextContent("Frame over Time", "Controls the uv animation frame of each particle over its lifetime. On the horisontal axis you will find the lifetime. On the vertical axis you will find the sheet index."); + public GUIContent frameOverTime = EditorGUIUtility.TrTextContent("Frame over Time", "Controls the uv animation frame of each particle over its lifetime. On the horizontal axis you will find the lifetime. On the vertical axis you will find the sheet index."); public GUIContent startFrame = EditorGUIUtility.TrTextContent("Start Frame", "Phase the animation, so it starts on a frame other than 0."); public GUIContent speedRange = EditorGUIUtility.TrTextContent("Speed Range", "Remaps speed in the defined range to a 0-1 value through the animation."); public GUIContent tiles = EditorGUIUtility.TrTextContent("Tiles", "Defines the tiling of the texture."); diff --git a/Modules/ParticleSystemEditor/ParticleSystemUI.cs b/Modules/ParticleSystemEditor/ParticleSystemUI.cs index a8a34ef469..d91a062901 100644 --- a/Modules/ParticleSystemEditor/ParticleSystemUI.cs +++ b/Modules/ParticleSystemEditor/ParticleSystemUI.cs @@ -20,6 +20,10 @@ internal class ParticleSystemUI private static string[] s_ModuleNames; private string m_SupportsCullingText; private string m_SupportsCullingTextLabel; // Cached version including bullet points + private int m_CachedMeshInstanceID; + private int m_CachedMaterialInstanceID; + private int m_CachedMeshDirtyCount; + private int m_CachedMaterialDirtyCount; private static PrefColor s_BoundsColor = new PrefColor("Particle System/Bounds", 1.0f, 235.0f / 255.0f, 4.0f / 255.0f, 1.0f); @@ -203,23 +207,46 @@ public void OnGUI(float width, bool fixedWidth) if (isRepaintEvent && renderer != null) { bool iconRendered = false; - int instanceID = 0; if (!multiEdit) { + int instanceID = 0; + if (renderer.renderMode == ParticleSystemRenderMode.Mesh) { if (renderer.mesh != null) + { instanceID = renderer.mesh.GetInstanceID(); + + // If the asset is dirty we ensure to get a updated one by clearing cache of temporary previews + if (m_CachedMeshInstanceID != instanceID) + { + m_CachedMeshInstanceID = instanceID; + m_CachedMeshDirtyCount = -1; + } + if (EditorUtility.GetDirtyCount(instanceID) != m_CachedMeshDirtyCount) + { + AssetPreview.ClearTemporaryAssetPreviews(); + m_CachedMeshDirtyCount = EditorUtility.GetDirtyCount(instanceID); + } + } } else if (renderer.sharedMaterial != null) { instanceID = renderer.sharedMaterial.GetInstanceID(); - } - // If the asset is dirty we ensure to get a updated one by clearing cache of temporary previews - if (EditorUtility.IsDirty(instanceID)) - AssetPreview.ClearTemporaryAssetPreviews(); + // If the asset is dirty we ensure to get a updated one by clearing cache of temporary previews + if (m_CachedMaterialInstanceID != instanceID) + { + m_CachedMaterialInstanceID = instanceID; + m_CachedMaterialDirtyCount = -1; + } + if (EditorUtility.GetDirtyCount(instanceID) != m_CachedMaterialDirtyCount) + { + AssetPreview.ClearTemporaryAssetPreviews(); + m_CachedMaterialDirtyCount = EditorUtility.GetDirtyCount(instanceID); + } + } if (instanceID != 0) { diff --git a/Modules/Physics2D/ScriptBindings/Physics2D.bindings.cs b/Modules/Physics2D/ScriptBindings/Physics2D.bindings.cs index 1acc25b383..52229980df 100644 --- a/Modules/Physics2D/ScriptBindings/Physics2D.bindings.cs +++ b/Modules/Physics2D/ScriptBindings/Physics2D.bindings.cs @@ -3725,6 +3725,9 @@ public enum GenerationType { Synchronous = 0, Manual = 1 } // extern public radius of the edge(s). extern public float edgeRadius { get; set; } + // Controls the distance in which vertices are offset and clipped if within this distance + extern public float offsetDistance { get; set; } + // Generates the geometry if using manual generation type. extern public void GenerateGeometry(); diff --git a/Modules/PresetsEditor/PresetEditor.cs b/Modules/PresetsEditor/PresetEditor.cs index e7bd3137c1..770c82512c 100644 --- a/Modules/PresetsEditor/PresetEditor.cs +++ b/Modules/PresetsEditor/PresetEditor.cs @@ -32,6 +32,7 @@ class ReferenceCount static Dictionary s_References = new Dictionary(); + List m_PresetsInstanceIds = new List(); bool m_DisplayErrorPreset; string m_SelectedPresetTypeName; Dictionary> m_InspectedTypes = new Dictionary>(); @@ -159,6 +160,7 @@ void GenerateInternalEditor() return; } s_References.Add(p.GetInstanceID(), reference); + m_PresetsInstanceIds.Add(p.GetInstanceID()); } reference.count++; objs[index] = reference.reference; @@ -172,22 +174,23 @@ void DestroyInternalEditor() if (m_InternalEditor != null) { DestroyImmediate(m_InternalEditor); - for (var index = 0; index < targets.Length; index++) + // On Destroy, look for instances id instead of target because they may already be null. + for (var index = 0; index < m_PresetsInstanceIds.Count; index++) { - var p = (Preset)targets[index]; - if (--s_References[p.GetInstanceID()].count == 0) + var instanceId = m_PresetsInstanceIds[index]; + if (--s_References[instanceId].count == 0) { - if (s_References[p.GetInstanceID()].reference is Component) + if (s_References[instanceId].reference is Component) { - var go = ((Component)s_References[p.GetInstanceID()].reference).gameObject; + var go = ((Component)s_References[instanceId].reference).gameObject; go.hideFlags = HideFlags.None; // make sure we remove the don't destroy flag before calling destroy DestroyImmediate(go); } else { - DestroyImmediate(s_References[p.GetInstanceID()].reference); + DestroyImmediate(s_References[instanceId].reference); } - s_References.Remove(p.GetInstanceID()); + s_References.Remove(instanceId); } } } diff --git a/Modules/ProfilerEditor/ProfilerWindow/Chart.cs b/Modules/ProfilerEditor/ProfilerWindow/Chart.cs index d13f1d90c9..350141a03f 100644 --- a/Modules/ProfilerEditor/ProfilerWindow/Chart.cs +++ b/Modules/ProfilerEditor/ProfilerWindow/Chart.cs @@ -301,8 +301,7 @@ private void DrawOverlayBoxes(ChartViewData cdata, Rect r, bool chartActive) { if (Event.current.type == EventType.Repaint && cdata.dataAvailable != null) { - r.height += 2; - r.y -= 1; + r.height += 1; int lastFrameWithData = 0; int frameDataLength = cdata.dataAvailable.Length; @@ -325,20 +324,18 @@ private void DrawOverlayBoxes(ChartViewData cdata, Rect r, bool chartActive) } } - private void DrawOverlayBox(Rect r, int startFrame, int endFrame, int frameDataLength, bool chartActive, GUIStyle style, GUIContent content = null) + private void DrawOverlayBox(Rect r, int startFrame, int endFrame, int frameDataLength, bool chartActive, GUIStyle style) { float gracePixels = -1; float domainSize = frameDataLength - 1; - float startYOffest = Mathf.RoundToInt(r.width * startFrame / domainSize) + gracePixels; - float endYOffest = Mathf.RoundToInt(r.width * endFrame / domainSize) - gracePixels; + float startXOffest = Mathf.RoundToInt(r.width * startFrame / domainSize) + gracePixels; + float endXOffest = Mathf.RoundToInt(r.width * endFrame / domainSize) - gracePixels; Rect noDataRect = r; - noDataRect.x += Mathf.Max(startYOffest, 0); - noDataRect.width = Mathf.Min(endYOffest - startYOffest, r.width - (noDataRect.x - r.x)); + noDataRect.x += Mathf.Max(startXOffest, 0); + noDataRect.width = Mathf.Min(endXOffest - startXOffest, r.width - (noDataRect.x - r.x)); style.Draw(noDataRect, false, false, chartActive, false); - if (content != null) - GUI.Box(noDataRect, content); } private void DrawChartStacked(int selectedFrame, ChartViewData cdata, Rect r, bool chartActive) @@ -503,8 +500,7 @@ private void DrawLabels(Rect chartPosition, ChartViewData data, int selectedFram if (stacked) { var accumulatedValues = 0f; - //if the current series is non stackable a.k.a "Others" then just add up all other series - int currentChartIndex = s == data.unstackableSeriesIndex ? data.series.Length : m_LabelOrder.FindIndex(x => x == s); + int currentChartIndex = m_LabelOrder.FindIndex(x => x == s); for (int i = currentChartIndex - 1; i >= 0; --i) { @@ -512,8 +508,7 @@ private void DrawLabels(Rect chartPosition, ChartViewData data, int selectedFram var otherChartData = data.hasOverlay ? data.overlays[otherSeriesIdx] : data.series[otherSeriesIdx]; bool enabled = data.series[otherSeriesIdx].enabled; - // account for "non stackable category" - if (enabled && otherSeriesIdx != data.unstackableSeriesIndex) + if (enabled) { accumulatedValues += otherChartData.yValues[selectedIndex] * otherChartData.yScale; } @@ -772,7 +767,7 @@ private void DrawChartItemStacked(Rect r, int index, ChartViewData cdata, float[ for (int i = 0; i < numSamples; i++, x += step) { float y = rectBottom - stackedSampleSums[i]; - var serie = cdata.unstackableSeriesIndex == index && cdata.hasOverlay ? cdata.overlays[index] : cdata.series[index]; + var serie = cdata.series[index]; float value = serie.yValues[i] * serie.yScale; if (value == -1f) continue; @@ -1043,15 +1038,8 @@ internal class ChartViewData public int numSeries { get; private set; } public int chartDomainOffset { get; private set; } - public int unstackableSeriesIndex { get; private set; } - - public void Assign(ChartSeriesViewData[] series, int unstackableSeriesIndex, int firstFrame, int firstSelectableFrame) + public void Assign(ChartSeriesViewData[] series, int firstFrame, int firstSelectableFrame) { - if (unstackableSeriesIndex != -1) - { - this.unstackableSeriesIndex = unstackableSeriesIndex; - } - this.series = series; this.chartDomainOffset = firstFrame; this.firstSelectableFrame = firstSelectableFrame; diff --git a/Modules/ProfilerEditor/ProfilerWindow/ProfilerColors.cs b/Modules/ProfilerEditor/ProfilerWindow/ProfilerColors.cs index 583e7fec40..d3416017ec 100644 --- a/Modules/ProfilerEditor/ProfilerWindow/ProfilerColors.cs +++ b/Modules/ProfilerEditor/ProfilerWindow/ProfilerColors.cs @@ -13,42 +13,126 @@ internal class ProfilerColors { static ProfilerColors() { + s_DefaultColors = new Color[] + { + HierarchyFrameDataView.GetMarkerCategoryColor(0), // "Render" + HierarchyFrameDataView.GetMarkerCategoryColor(1), // "Scripts" + HierarchyFrameDataView.GetMarkerCategoryColor(2), // "Managed Jobs" + HierarchyFrameDataView.GetMarkerCategoryColor(3), // "Burst Jobs" + HierarchyFrameDataView.GetMarkerCategoryColor(4), // "GUI" + HierarchyFrameDataView.GetMarkerCategoryColor(5), // "Physics" + HierarchyFrameDataView.GetMarkerCategoryColor(6), // "Animation" + HierarchyFrameDataView.GetMarkerCategoryColor(7), // "AI" + HierarchyFrameDataView.GetMarkerCategoryColor(8), // "Audio" + HierarchyFrameDataView.GetMarkerCategoryColor(9), // "Audio Job" + HierarchyFrameDataView.GetMarkerCategoryColor(10), // "Audio Update Job + HierarchyFrameDataView.GetMarkerCategoryColor(11), // "Video" + HierarchyFrameDataView.GetMarkerCategoryColor(12), // "Particles" + HierarchyFrameDataView.GetMarkerCategoryColor(13), // "Gi" + HierarchyFrameDataView.GetMarkerCategoryColor(14), // "Network" + HierarchyFrameDataView.GetMarkerCategoryColor(15), // "Loading" + HierarchyFrameDataView.GetMarkerCategoryColor(16), // "Other" + HierarchyFrameDataView.GetMarkerCategoryColor(17), // "GC" + HierarchyFrameDataView.GetMarkerCategoryColor(18), // "VSync" + HierarchyFrameDataView.GetMarkerCategoryColor(19), // "Overhead" + HierarchyFrameDataView.GetMarkerCategoryColor(20), // "PlayerLoop" + HierarchyFrameDataView.GetMarkerCategoryColor(21), // "Director" + HierarchyFrameDataView.GetMarkerCategoryColor(22), // "VR" + HierarchyFrameDataView.GetMarkerCategoryColor(23), // "NativeMem" + HierarchyFrameDataView.GetMarkerCategoryColor(24), // "Internal" + HierarchyFrameDataView.GetMarkerCategoryColor(25), // "FileIO" + HierarchyFrameDataView.GetMarkerCategoryColor(26), // "UI Layout" + HierarchyFrameDataView.GetMarkerCategoryColor(27), // "UI Render" + HierarchyFrameDataView.GetMarkerCategoryColor(28), // "VFX" + HierarchyFrameDataView.GetMarkerCategoryColor(29), // "Build Interface" + HierarchyFrameDataView.GetMarkerCategoryColor(30), // "Input" + }; + s_DefaultColorsLuminanceValues = new float[s_DefaultColors.Length]; + VisionUtility.GetLuminanceValuesForPalette(s_DefaultColors, ref s_DefaultColorsLuminanceValues); // Areas are defined by stats in ProfilerStats.cpp file. // Color are driven by CPU profiler chart area colors and must be consistent with CPU timeline sample colors. // Sample color is defined by ProfilerGroup (category) and defined in s_ProfilerGroupInfos table. - s_DefaultColors = new Color[] + s_DefaultChartColors = new Color[] { - HierarchyFrameDataView.GetMarkerCategoryColor(0), // "Rendering" - HierarchyFrameDataView.GetMarkerCategoryColor(1), // "Scripts" - HierarchyFrameDataView.GetMarkerCategoryColor(5), // "Physics" - HierarchyFrameDataView.GetMarkerCategoryColor(6), // "Animation" - HierarchyFrameDataView.GetMarkerCategoryColor(17), // "GarbageCollector" - HierarchyFrameDataView.GetMarkerCategoryColor(18), // "VSync" - HierarchyFrameDataView.GetMarkerCategoryColor(13), // "Global Illumination" - HierarchyFrameDataView.GetMarkerCategoryColor(26), // "UI" - new Color(122.0f / 255.0f, 123.0f / 255.0f, 30.0f / 255.0f, 1.0f), // "Others" + s_DefaultColors[0], // "Rendering" + s_DefaultColors[1], // "Scripts" + s_DefaultColors[5], // "Physics" + s_DefaultColors[6], // "Animation" + s_DefaultColors[17], // "GarbageCollector" + s_DefaultColors[18], // "VSync" + s_DefaultColors[13], // "Global Illumination" + s_DefaultColors[26], // "UI" + s_DefaultColors[16], // "Others" + // Colors below are currently only used in Timeline view + s_DefaultColors[8], // "Audio" + s_DefaultColors[9], // "Audio Job" + s_DefaultColors[10], // "Audio Update Job" + s_DefaultColors[23], // "Memory Alloc" + s_DefaultColors[24], // "Internal" + s_DefaultColors[29], // "Build Interface" + s_DefaultColors[30], // "Input" + }; + s_ColorBlindSafeChartColors = new Color[s_DefaultChartColors.Length]; + VisionUtility.GetColorBlindSafePalette(s_ColorBlindSafeChartColors, 0.3f, 1f); - new Color(240.0f / 255.0f, 128.0f / 255.0f, 128.0f / 255.0f, 1.0f), // light-coral - new Color(169.0f / 255.0f, 169.0f / 255.0f, 169.0f / 255.0f, 1.0f), // dark-gray - new Color(139.0f / 255.0f, 0.0f, 139.0f / 255.0f, 1.0f), // dark-magenta - new Color(255.0f / 255.0f, 228.0f / 255.0f, 181.0f / 255.0f, 1.0f), // moccasin - new Color(32.0f / 255.0f, 178.0f / 255.0f, 170.0f / 255.0f, 1.0f), // light-sea-green - new Color(0.4831376f, 0.6211768f, 0.0219608f, 1.0f), - new Color(0.3827448f, 0.2886272f, 0.5239216f, 1.0f), - new Color(0.8f, 0.4423528f, 0.0f, 1.0f), - new Color(0.4486272f, 0.4078432f, 0.050196f, 1.0f), - new Color(0.4831376f, 0.6211768f, 0.0219608f, 1.0f), + s_ColorBlindSafeColors = new Color[] + { + s_ColorBlindSafeChartColors[0], // "Render" + s_ColorBlindSafeChartColors[1], // "Scripts" + s_ColorBlindSafeChartColors[1], // "Managed Jobs" + s_ColorBlindSafeChartColors[1], // "Burst Jobs" + s_ColorBlindSafeChartColors[8], // "GUI" + s_ColorBlindSafeChartColors[3], // "Physics" + s_ColorBlindSafeChartColors[4], // "Animation" + s_ColorBlindSafeChartColors[8], // "AI" + s_ColorBlindSafeChartColors[9], // "Audio" + s_ColorBlindSafeChartColors[10], // "Audio Job" + s_ColorBlindSafeChartColors[11], // "Audio Update Job + s_ColorBlindSafeChartColors[8], // "Video" + s_ColorBlindSafeChartColors[8], // "Particles" + s_ColorBlindSafeChartColors[6], // "Gi" + s_ColorBlindSafeChartColors[8], // "Network" + s_ColorBlindSafeChartColors[8], // "Loading" + s_ColorBlindSafeChartColors[8], // "Other" + s_ColorBlindSafeChartColors[4], // "GC" + s_ColorBlindSafeChartColors[5], // "VSync" + s_ColorBlindSafeChartColors[8], // "Overhead" + s_ColorBlindSafeChartColors[8], // "PlayerLoop" + s_ColorBlindSafeChartColors[8], // "Director" + s_ColorBlindSafeChartColors[8], // "VR" + s_ColorBlindSafeChartColors[12], // "NativeMem" + s_ColorBlindSafeChartColors[13], // "Internal" + s_ColorBlindSafeChartColors[8], // "FileIO" + s_ColorBlindSafeChartColors[7], // "UI Layout" + s_ColorBlindSafeChartColors[7], // "UI Render" + s_ColorBlindSafeChartColors[8], // "VFX" + s_ColorBlindSafeChartColors[14], // "Build Interface" + s_ColorBlindSafeChartColors[15], // "Input" }; - s_ColorBlindSafeColors = new Color[s_DefaultColors.Length]; - VisionUtility.GetColorBlindSafePalette(s_ColorBlindSafeColors, 0.3f, 1f); + s_ColorBlindSafeColorsLuminanceValues = new float[s_ColorBlindSafeColors.Length]; + VisionUtility.GetLuminanceValuesForPalette(s_ColorBlindSafeColors, ref s_ColorBlindSafeColorsLuminanceValues); } public static Color[] chartAreaColors + { + get { return UserAccessiblitySettings.colorBlindCondition == ColorBlindCondition.Default ? s_DefaultChartColors : s_ColorBlindSafeChartColors; } + } + + public static Color[] timelineColors { get { return UserAccessiblitySettings.colorBlindCondition == ColorBlindCondition.Default ? s_DefaultColors : s_ColorBlindSafeColors; } } - private static readonly Color[] s_DefaultColors; - private static readonly Color[] s_ColorBlindSafeColors; + public static float[] timelineColorsLuminance + { + get { return UserAccessiblitySettings.colorBlindCondition == ColorBlindCondition.Default ? s_DefaultColorsLuminanceValues : s_ColorBlindSafeColorsLuminanceValues; } + } + + static readonly Color[] s_DefaultColors; + static readonly float[] s_DefaultColorsLuminanceValues; + static readonly Color[] s_ColorBlindSafeColors; + static readonly float[] s_ColorBlindSafeColorsLuminanceValues; + static readonly Color[] s_DefaultChartColors; + static readonly Color[] s_ColorBlindSafeChartColors; } } diff --git a/Modules/ProfilerEditor/ProfilerWindow/ProfilerDetailedCallsView.cs b/Modules/ProfilerEditor/ProfilerWindow/ProfilerDetailedCallsView.cs index 659d2ec350..5d914d5b62 100644 --- a/Modules/ProfilerEditor/ProfilerWindow/ProfilerDetailedCallsView.cs +++ b/Modules/ProfilerEditor/ProfilerWindow/ProfilerDetailedCallsView.cs @@ -383,8 +383,8 @@ static class Styles public static GUIContent calleesLabel = EditorGUIUtility.TrTextContent("Calls To", "Functions which are called from the selected function\n\n(Press 'F' for frame selection)"); public static GUIContent callsLabel = EditorGUIUtility.TrTextContent("Calls", "Total number of calls in a selected frame"); public static GUIContent gcAllocLabel = EditorGUIUtility.TrTextContent("GC Alloc"); - public static GUIContent timeMsCallersLabel = EditorGUIUtility.TrTextContent("Time ms", "Total time the selected function spend within a parent"); - public static GUIContent timeMsCalleesLabel = EditorGUIUtility.TrTextContent("Time ms", "Total time the child call spend within selected function"); + public static GUIContent timeMsCallersLabel = EditorGUIUtility.TrTextContent("Time ms", "Total time the selected function spends within a parent"); + public static GUIContent timeMsCalleesLabel = EditorGUIUtility.TrTextContent("Time ms", "Total time the child call spends within selected function"); public static GUIContent timePctCallersLabel = EditorGUIUtility.TrTextContent("Time %", "Shows how often the selected function was called from the parent call"); public static GUIContent timePctCalleesLabel = EditorGUIUtility.TrTextContent("Time %", "Shows how often child call was called from the selected function"); } diff --git a/Modules/ProfilerEditor/ProfilerWindow/ProfilerFrameDataTreeView.cs b/Modules/ProfilerEditor/ProfilerWindow/ProfilerFrameDataTreeView.cs index 455d23da8a..53d2191c7f 100644 --- a/Modules/ProfilerEditor/ProfilerWindow/ProfilerFrameDataTreeView.cs +++ b/Modules/ProfilerEditor/ProfilerWindow/ProfilerFrameDataTreeView.cs @@ -129,6 +129,7 @@ public void Init(ProfilerFrameDataMultiColumnHeader.Column[] columns) public ProfilerFrameDataTreeView(TreeViewState state, ProfilerFrameDataMultiColumnHeader multicolumnHeader) : base(state, multicolumnHeader) { Assert.IsNotNull(multicolumnHeader); + deselectOnUnhandledMouseDown = true; m_MultiColumnHeader = multicolumnHeader; m_MultiColumnHeader.sortingChanged += OnSortingChanged; } diff --git a/Modules/ProfilerEditor/ProfilerWindow/ProfilerTimelineGUI.cs b/Modules/ProfilerEditor/ProfilerWindow/ProfilerTimelineGUI.cs index 5515f0daf6..ee4a086088 100644 --- a/Modules/ProfilerEditor/ProfilerWindow/ProfilerTimelineGUI.cs +++ b/Modules/ProfilerEditor/ProfilerWindow/ProfilerTimelineGUI.cs @@ -12,6 +12,8 @@ using UnityEditor.AnimatedValues; using Unity.Profiling; using System.Globalization; +using UnityEditor.Accessibility; +using Unity.Collections.LowLevel.Unsafe; namespace UnityEditorInternal { @@ -32,7 +34,7 @@ internal class ProfilerTimelineGUI : ProfilerFrameDataViewBase const string k_TickFormatSeconds = "{0}s"; const int k_TickLabelSeparation = 60; - internal class ThreadInfo + internal class ThreadInfo : IComparable { public float height = 0; public float linesToDisplay = 2f; @@ -47,6 +49,13 @@ public ThreadInfo(string name, int threadIndex, int maxDepth, int linesToDisplay this.linesToDisplay = linesToDisplay; this.maxDepth = Mathf.Max(1, maxDepth); } + + public int CompareTo(ThreadInfo other) + { + if (this == other) + return 0; + return EditorUtility.NaturalCompare(name, other.name); + } } internal class GroupInfo @@ -152,7 +161,8 @@ public virtual void Reset() private class SelectedEntryInfo : EntryInfo { - public int instanceId = -1; + // The associated GameObjects instance ID. Negative means Native Object, Positive means Managed Object, 0 means not set (as in, no object associated) + public int instanceId = 0; public string metaData = string.Empty; public float totalDuration = -1.0f; @@ -163,7 +173,7 @@ public override void Reset() { base.Reset(); - this.instanceId = -1; + this.instanceId = 0; this.metaData = string.Empty; this.totalDuration = -1.0f; @@ -285,6 +295,11 @@ private void UpdateGroupAndThreadInfo(ref ProfilerFrameDataIterator iter, int fr } thread.alive = true; } + foreach (var group in m_Groups) + { + group.threads.Sort(); + } + m_LastSelectedFrameID = frameIndex; } @@ -581,7 +596,7 @@ private void PerformFrameSelected(float frameMS, bool verticallyFrameSelected = { t = m_SelectedEntry.time; dt = m_SelectedEntry.duration; - if (m_SelectedEntry.instanceId < 0 || dt <= 0.0f) + if (m_SelectedEntry.instanceCount <= 0 || dt <= 0.0f) { t = 0.0f; dt = frameMS; @@ -590,7 +605,7 @@ private void PerformFrameSelected(float frameMS, bool verticallyFrameSelected = m_TimeArea.SetShownHRangeInsideMargins(t - dt * 0.2f, t + dt * 1.2f); - if (verticallyFrameSelected && m_SelectedEntry.instanceId >= 0) + if (m_SelectedEntry.instanceCount >= 0 && verticallyFrameSelected) { if (m_SelectedEntry.relativeYPos > m_SelectedThread.height) { @@ -1230,7 +1245,7 @@ public void DoGUI(HierarchyFrameDataView frameDataView, float width, float ypos, if (initializing) { - NativeProfilerTimeline_InitializeArgs args = new NativeProfilerTimeline_InitializeArgs(); + var args = new NativeProfilerTimeline_InitializeArgs(); args.Reset(); args.ghostAlpha = 0.3f; args.nonSelectedAlpha = 0.75f; @@ -1239,6 +1254,14 @@ public void DoGUI(HierarchyFrameDataView frameDataView, float width, float ypos, args.textFadeOutWidth = k_TextFadeOutWidth; args.textFadeStartWidth = k_TextFadeStartWidth; + var timelineColors = ProfilerColors.timelineColors; + args.profilerColorDescriptors = new ProfilerColorDescriptor[timelineColors.Length]; + + for (int i = 0; i < timelineColors.Length; ++i) + { + args.profilerColorDescriptors[i] = new ProfilerColorDescriptor(timelineColors[i]); + } + NativeProfilerTimeline.Initialize(ref args); } // Prepare group and Thread Info @@ -1256,7 +1279,7 @@ public void DoGUI(HierarchyFrameDataView frameDataView, float width, float ypos, float emptySpaceBelowBars = k_LineHeight * 3f; // if needed, take up more empty space below, to fill up the ZoomableArea - emptySpaceBelowBars = Mathf.Max(emptySpaceBelowBars, timeAreaRect.height - heightForAllBars); + emptySpaceBelowBars = Mathf.Max(emptySpaceBelowBars, timeAreaRect.height - m_TimeArea.hSliderHeight - heightForAllBars); heightForAllBars += emptySpaceBelowBars; diff --git a/Modules/ProfilerEditor/ProfilerWindow/ProfilerWindow.cs b/Modules/ProfilerEditor/ProfilerWindow/ProfilerWindow.cs index 0177dbea8f..efb7e7d80b 100644 --- a/Modules/ProfilerEditor/ProfilerWindow/ProfilerWindow.cs +++ b/Modules/ProfilerEditor/ProfilerWindow/ProfilerWindow.cs @@ -84,8 +84,6 @@ static Styles() profilerGraphBackground.overflow.left = -(int)Chart.kSideWidth; } } - - private const string k_CPUUnstackableSeriesName = "Others"; private static readonly ProfilerArea[] ms_StackedAreas = { ProfilerArea.CPU, ProfilerArea.GPU, ProfilerArea.UI, ProfilerArea.GlobalIllumination }; [NonSerialized] @@ -123,7 +121,9 @@ static Styles() ProfilerViewType m_ViewType = ProfilerViewType.Timeline; [SerializeField] - ProfilerArea? m_CurrentArea = ProfilerArea.CPU; + ProfilerArea m_CurrentArea = k_InvalidArea; + + const ProfilerArea k_InvalidArea = unchecked((ProfilerArea)Profiler.invalidProfilerArea); ProfilerMemoryView m_ShowDetailedMemoryPane = ProfilerMemoryView.Simple; ProfilerAudioView m_ShowDetailedAudioPane = ProfilerAudioView.Channels; @@ -292,7 +292,7 @@ void Initialize() m_Charts = new ProfilerChart[Profiler.areaCount]; - Color[] chartAreaColors = ProfilerColors.chartAreaColors; + var chartAreaColors = ProfilerColors.chartAreaColors; for (int i = 0; i < Profiler.areaCount; i++) { @@ -323,6 +323,19 @@ void Initialize() m_Charts[(int)i] = chart; } + + if (m_CurrentArea == k_InvalidArea || !m_Charts[(int)m_CurrentArea].active) + { + for (int i = 0; i < m_Charts.Length; i++) + { + if (m_Charts[i].active) + { + m_CurrentArea = (ProfilerArea)i; + break; + } + } + } + if (m_VertSplit == null || m_VertSplit.relativeSizes == null || m_VertSplit.relativeSizes.Length == 0) m_VertSplit = new SplitterState(new[] { 50f, 50f }, new[] { k_VertSplitterMinSizes, k_VertSplitterMinSizes }, null); // 2 times the min splitter size plus one line height for the toolbar up top @@ -399,19 +412,23 @@ ProfilerChart CreateProfilerChart(ProfilerArea i, Chart.ChartType chartType, flo void OnChartClosed(Chart sender) { - var currentAreaChart = m_Charts[(int)m_CurrentArea]; - if (currentAreaChart == sender) + ProfilerChart profilerChart = (ProfilerChart)sender; + if (m_CurrentArea != k_InvalidArea) { - m_CurrentArea = null; - m_UISystemProfiler.CurrentAreaChanged(m_CurrentArea); + var currentAreaChart = m_Charts[(int)m_CurrentArea]; + if (currentAreaChart == sender) + { + m_CurrentArea = k_InvalidArea; + m_UISystemProfiler.CurrentAreaChanged(m_CurrentArea); + } } - ProfilerChart profilerChart = (ProfilerChart)sender; + m_CurrentArea = k_InvalidArea; profilerChart.active = false; } void OnChartSelected(Chart sender) { - ProfilerArea? newArea = null; + ProfilerArea newArea = k_InvalidArea; for (int i = 0, numCharts = m_Charts.Length; i < numCharts; ++i) { if (m_Charts[i] == sender) @@ -710,11 +727,11 @@ static Rect GenerateRect(ref int row, int indent) void DrawNetworkOperationsPane() { - if (!m_CurrentArea.HasValue) + if (m_CurrentArea == k_InvalidArea) return; SplitterGUILayout.BeginHorizontalSplit(m_NetworkSplit); - GUILayout.Label(ProfilerDriver.GetOverviewText(m_CurrentArea.Value, GetActiveVisibleFrameIndex()), EditorStyles.wordWrappedLabel); + GUILayout.Label(ProfilerDriver.GetOverviewText(m_CurrentArea, GetActiveVisibleFrameIndex()), EditorStyles.wordWrappedLabel); m_PaneScroll[(int)m_CurrentArea] = GUILayout.BeginScrollView(m_PaneScroll[(int)m_CurrentArea], Styles.background); @@ -804,8 +821,10 @@ private Rect DrawAudioStatsPane(ref Vector2 scrollPos) var statsRect = new Rect(totalRect.x, totalRect.y, 230f, totalRect.height); var rightRect = new Rect(statsRect.xMax, totalRect.y, totalRect.width - statsRect.width, totalRect.height); + if (m_CurrentArea == k_InvalidArea) + return rightRect; // STATS - var content = ProfilerDriver.GetOverviewText(m_CurrentArea.Value, GetActiveVisibleFrameIndex()); + var content = ProfilerDriver.GetOverviewText(m_CurrentArea, GetActiveVisibleFrameIndex()); var textSize = EditorStyles.wordWrappedLabel.CalcSize(GUIContent.Temp(content)); scrollPos = GUI.BeginScrollView(statsRect, scrollPos, new Rect(0, 0, textSize.x, textSize.y)); GUI.Label(new Rect(3, 3, textSize.x, textSize.y), content, EditorStyles.wordWrappedLabel); @@ -1101,8 +1120,7 @@ private void ComputeChartScaleValue(ProfilerArea i, int historyLength, int first float timeNow = 0.0F; for (int j = 0; j < chart.m_Series.Length; j++) { - var series = chart.m_Data.unstackableSeriesIndex == j && chart.m_Data.hasOverlay ? - chart.m_Data.overlays[j] : chart.m_Series[j]; + var series = chart.m_Series[j]; if (series.enabled) timeNow += series.yValues[k]; @@ -1130,7 +1148,6 @@ private void ComputeChartScaleValue(ProfilerArea i, int historyLength, int first internal static void UpdateSingleChart(ProfilerChart chart, int firstEmptyFrame, int firstFrame) { float totalMaxValue = 1; - int unstackableChartIndex = -1; var maxValues = new float[chart.m_Series.Length]; for (int i = 0, count = chart.m_Series.Length; i < count; ++i) { @@ -1156,14 +1173,6 @@ internal static void UpdateSingleChart(ProfilerChart chart, int firstEmptyFrame, else { maxValues[i] = maxValue; - if (chart.m_Area == ProfilerArea.CPU) - { - if (chart.m_Series[i].name == k_CPUUnstackableSeriesName) - { - unstackableChartIndex = i; - break; - } - } } } if (chart.m_Area == ProfilerArea.NetworkMessages || chart.m_Area == ProfilerArea.NetworkOperations) @@ -1172,7 +1181,7 @@ internal static void UpdateSingleChart(ProfilerChart chart, int firstEmptyFrame, chart.m_Series[i].rangeAxis = new Vector2(0f, 0.9f * totalMaxValue); chart.m_Data.maxValue = totalMaxValue; } - chart.m_Data.Assign(chart.m_Series, unstackableChartIndex, firstEmptyFrame, firstFrame); + chart.m_Data.Assign(chart.m_Series, firstEmptyFrame, firstFrame); ProfilerDriver.GetStatisticsAvailable(chart.m_Area, firstEmptyFrame, chart.m_Data.dataAvailable); if (chart is UISystemProfilerChart) @@ -1344,6 +1353,7 @@ void Clear() m_GPUFrameDataHierarchyView.Clear(); ProfilerDriver.ClearAllFrames(); + m_LastFrameFromTick = -1; #pragma warning disable CS0618 NetworkDetailStats.m_NetworkOperations.Clear(); @@ -1380,7 +1390,7 @@ private void FrameNavigationControls() } } - static void DrawOtherToolbar(ProfilerArea? area) + static void DrawOtherToolbar(ProfilerArea area) { EditorGUILayout.BeginHorizontal(EditorStyles.toolbar); if (area == ProfilerArea.Rendering) @@ -1397,12 +1407,12 @@ static void DrawOtherToolbar(ProfilerArea? area) EditorGUILayout.EndHorizontal(); } - private void DrawOverviewText(ProfilerArea? area) + private void DrawOverviewText(ProfilerArea area) { - if (!area.HasValue) + if (area == k_InvalidArea) return; - string activeText = ProfilerDriver.GetOverviewText(area.Value, GetActiveVisibleFrameIndex()); + string activeText = ProfilerDriver.GetOverviewText(area, GetActiveVisibleFrameIndex()); float height = EditorStyles.wordWrappedLabel.CalcHeight(GUIContent.Temp(activeText), position.width); m_PaneScroll[(int)area] = GUILayout.BeginScrollView(m_PaneScroll[(int)area], Styles.background); @@ -1410,7 +1420,7 @@ private void DrawOverviewText(ProfilerArea? area) GUILayout.EndScrollView(); } - private void DrawPane(ProfilerArea? area) + private void DrawPane(ProfilerArea area) { DrawOtherToolbar(area); DrawOverviewText(area); @@ -1486,17 +1496,17 @@ void OnGUI() DrawAudioPane(); break; case ProfilerArea.NetworkMessages: - DrawPane(m_CurrentArea.Value); + DrawPane(m_CurrentArea); break; case ProfilerArea.NetworkOperations: DrawNetworkOperationsPane(); break; case ProfilerArea.UI: case ProfilerArea.UIDetails: - m_UISystemProfiler.DrawUIPane(this, m_CurrentArea.Value, (UISystemProfilerChart)m_Charts[(int)ProfilerArea.UIDetails]); + m_UISystemProfiler.DrawUIPane(this, m_CurrentArea, (UISystemProfilerChart)m_Charts[(int)ProfilerArea.UIDetails]); break; - case null: + case k_InvalidArea: default: DrawPane(m_CurrentArea); break; diff --git a/Modules/ProfilerEditor/ProfilerWindow/UISystem/UISystemProfiler.cs b/Modules/ProfilerEditor/ProfilerWindow/UISystem/UISystemProfiler.cs index 98b91dd3bf..934331ef3e 100644 --- a/Modules/ProfilerEditor/ProfilerWindow/UISystem/UISystemProfiler.cs +++ b/Modules/ProfilerEditor/ProfilerWindow/UISystem/UISystemProfiler.cs @@ -27,6 +27,22 @@ internal class UISystemProfiler private int currentFrame = 0; + private Material previewTextureMaterial; + + public UISystemProfiler() + { + setupPreviewTextureMaterial(); + } + + internal void setupPreviewTextureMaterial() + { + if (previewTextureMaterial != null) + return; + + previewTextureMaterial = new Material(EditorGUI.transparentMaterial); + previewTextureMaterial.SetColor("_ColorMask", new Color(1, 1, 1, 1)); + } + internal void DrawUIPane(ProfilerWindow win, ProfilerArea profilerArea, UISystemProfilerChart detailsChart) { InitIfNeeded(win); @@ -189,8 +205,9 @@ internal void DrawRenderUI() EditorGUI.DrawRect(m_ZoomablePreview.drawRect, previewBackground == Styles.PreviewBackgroundType.Black ? Color.black : Color.white); } + Graphics.DrawTexture(m_ZoomablePreview.drawRect, image, m_ZoomablePreview.shownArea, 0, 0, 0, 0, - previewRenderMode == Styles.RenderMode.CompositeOverdraw ? m_CompositeOverdrawMaterial : EditorGUI.transparentMaterial); + previewRenderMode == Styles.RenderMode.CompositeOverdraw ? m_CompositeOverdrawMaterial : previewTextureMaterial); } if (previewRenderMode != Styles.RenderMode.Standard) break; diff --git a/Modules/ProfilerEditor/Public/NativeProfilerTimeline.bindings.cs b/Modules/ProfilerEditor/Public/NativeProfilerTimeline.bindings.cs index 19bd195ef3..eefb632f16 100644 --- a/Modules/ProfilerEditor/Public/NativeProfilerTimeline.bindings.cs +++ b/Modules/ProfilerEditor/Public/NativeProfilerTimeline.bindings.cs @@ -5,26 +5,42 @@ using System; using UnityEngine; using UnityEngine.Bindings; +using UnityEngine.Accessibility; namespace UnityEditorInternal { + public struct ProfilerColorDescriptor + { + public readonly Color color; + public readonly bool isBright; + const float k_LuminanceThreshold = 0.7f; + public ProfilerColorDescriptor(Color color) + { + this.color = color; + float lum = VisionUtility.ComputePerceivedLuminance(color); + isBright = lum >= k_LuminanceThreshold; + } + } + public struct NativeProfilerTimeline_InitializeArgs { public float ghostAlpha; public float nonSelectedAlpha; - public IntPtr guiStyle; public float lineHeight; public float textFadeOutWidth; public float textFadeStartWidth; + public IntPtr guiStyle; + public ProfilerColorDescriptor[] profilerColorDescriptors; public void Reset() { ghostAlpha = 0; nonSelectedAlpha = 0; - guiStyle = (IntPtr)0; + guiStyle = IntPtr.Zero; lineHeight = 0; textFadeOutWidth = 0; textFadeStartWidth = 0; + profilerColorDescriptors = null; } } diff --git a/Modules/ShortcutManagerEditor/ContextManager.cs b/Modules/ShortcutManagerEditor/ContextManager.cs index 46e2b9237f..18267bada9 100644 --- a/Modules/ShortcutManagerEditor/ContextManager.cs +++ b/Modules/ShortcutManagerEditor/ContextManager.cs @@ -33,6 +33,7 @@ internal class GlobalContext {} List m_PriorityContexts = new List(); List m_ToolContexts = new List(); + static Dictionary s_IsPriorityContextCache = new Dictionary(); public int activeContextCount => 1 + ((focusedWindow != null) ? 1 : 0) + m_PriorityContexts.Count(c => c.active) + m_ToolContexts.Count(c => c.active); @@ -60,7 +61,14 @@ static bool IsPriorityContext(IShortcutToolContext context) static bool IsPriorityContext(Type context) { - return Attribute.GetCustomAttribute(context, typeof(PriorityContextAttribute)) != null; + bool result; + if (!s_IsPriorityContextCache.TryGetValue(context, out result)) + { + result = Attribute.GetCustomAttribute(context, typeof(PriorityContextAttribute)) != null; + s_IsPriorityContextCache[context] = result; + } + + return result; } public bool DoContextsConflict(Type context1, Type context2) @@ -113,7 +121,7 @@ public void DeregisterToolContext(IShortcutToolContext context) if (context == null) return; - if (IsPriorityContext(context)) + if (m_PriorityContexts.Contains(context)) DeregisterPriorityContext(context); else { diff --git a/Modules/ShortcutManagerEditor/ShortcutController.cs b/Modules/ShortcutManagerEditor/ShortcutController.cs index d05be83071..c7e9988cca 100644 --- a/Modules/ShortcutManagerEditor/ShortcutController.cs +++ b/Modules/ShortcutManagerEditor/ShortcutController.cs @@ -6,10 +6,8 @@ using System.Collections.Generic; using System.IO; using UnityEngine; -using UnityEngine.Scripting; using Attribute = System.Attribute; using Event = UnityEngine.Event; -using UnityObject = UnityEngine.Object; namespace UnityEditor.ShortcutManagement { @@ -45,18 +43,27 @@ public string lastUsedProfileId } } - public static ShortcutController instance { get; private set; } + private static ShortcutController s_Instance; + public static ShortcutController instance + { + get + { + EnsureShortcutControllerCreated(); + return s_Instance; + } + } static ShortcutIntegration() { - InitializeController(); - EditorApplication.globalEventHandler += EventHandler; - EditorApplication.doPressedKeysTriggerAnyShortcut += HasAnyEntriesHandler; - - // Need to reinitialize after project load if we want menu items - EditorApplication.projectWasLoaded += InitializeController; + // There is cases where the ShortcutIntegration was not requested even after the project was initialized, such as running tests. + EditorApplication.delayCall += EnsureShortcutControllerCreated; + } - EditorApplication.focusChanged += OnFocusChanged; + static void EnsureShortcutControllerCreated() + { + if (s_Instance == null) + InitializeController(); + Debug.Assert(s_Instance != null); } static bool HasAnyEntriesHandler() @@ -86,19 +93,19 @@ static void InitializeController() var shortcutProviders = new IDiscoveryShortcutProvider[] { new ShortcutAttributeDiscoveryProvider(), - new ShortcutMenuItemDiscoveryProvider(), + new ShortcutMenuItemDiscoveryProvider() }; var bindingValidator = new BindingValidator(); var invalidContextReporter = new DiscoveryInvalidShortcutReporter(); var discovery = new Discovery(shortcutProviders, bindingValidator, invalidContextReporter); - instance = new ShortcutController(discovery, bindingValidator, new ShortcutProfileStore(), new LastUsedProfileIdProvider()); - instance.trigger.invokingAction += OnInvokingAction; - } + IContextManager contextManager = new ContextManager(); - [RequiredByNativeCode] - static void RebuildShortcuts() - { - instance.RebuildShortcuts(); + s_Instance = new ShortcutController(discovery, contextManager, bindingValidator, new ShortcutProfileStore(), new LastUsedProfileIdProvider()); + s_Instance.trigger.invokingAction += OnInvokingAction; + + EditorApplication.globalEventHandler += EventHandler; + EditorApplication.doPressedKeysTriggerAnyShortcut += HasAnyEntriesHandler; + EditorApplication.focusChanged += OnFocusChanged; } } @@ -114,15 +121,12 @@ class ShortcutController : IAvailableShortcutsChangedNotifier public IDirectory directory => m_Directory; public IBindingValidator bindingValidator { get; } public Trigger trigger { get; } - - ContextManager m_ContextManager = new ContextManager(); - - public IContextManager contextManager => m_ContextManager; + public IContextManager contextManager { get; } ILastUsedProfileIdProvider m_LastUsedProfileIdProvider; public event Action availableShortcutsChanged; - public ShortcutController(IDiscovery discovery, IBindingValidator bindingValidator, IShortcutProfileStore profileStore, ILastUsedProfileIdProvider lastUsedProfileIdProvider) + public ShortcutController(IDiscovery discovery, IContextManager contextManager, IBindingValidator bindingValidator, IShortcutProfileStore profileStore, ILastUsedProfileIdProvider lastUsedProfileIdProvider) { m_Discovery = discovery; this.bindingValidator = bindingValidator; @@ -136,6 +140,7 @@ public ShortcutController(IDiscovery discovery, IBindingValidator bindingValidat var conflictResolverView = new ConflictResolverView(); var conflictResolver = new ConflictResolver(profileManager, contextManager, conflictResolverView); + this.contextManager = contextManager; m_Directory = new Directory(profileManager.GetAllShortcuts()); trigger = new Trigger(m_Directory, conflictResolver); @@ -165,9 +170,6 @@ void HandleModeChanged(ModeService.ModeChangedArgs args) if (shortcutProfiles == null || shortcutProfiles.Count == 0) return; - // Rebuild shortcuts so all shortcuts bound to invisible menu items are removed. - RebuildShortcuts(); - string defaultMode = null; try { @@ -255,7 +257,7 @@ void LoadProfileById(string profileId) static bool TryParseUniquePrefKeyString(string prefString, out string name, out Event keyboardEvent, out string shortcut) { - int i = prefString.IndexOf(";"); + int i = prefString.IndexOf(";", StringComparison.Ordinal); if (i < 0) { name = null; diff --git a/Modules/ShortcutManagerEditor/ShortcutManagerWindowView.cs b/Modules/ShortcutManagerEditor/ShortcutManagerWindowView.cs index fea6aa87bb..78ec754693 100644 --- a/Modules/ShortcutManagerEditor/ShortcutManagerWindowView.cs +++ b/Modules/ShortcutManagerEditor/ShortcutManagerWindowView.cs @@ -889,7 +889,7 @@ public Keyboard(IKeyBindingStateProvider keyBindingStateProvider, KeyCode initia new KeyDef(KeyCode.P), new KeyDef(KeyCode.LeftBracket, "["), new KeyDef(KeyCode.RightBracket, "]"), - new KeyDef(KeyCode.Slash, "\\") + new KeyDef(KeyCode.Backslash, "\\") }, new[] { @@ -919,7 +919,7 @@ public Keyboard(IKeyBindingStateProvider keyBindingStateProvider, KeyCode initia new KeyDef(KeyCode.M), new KeyDef(KeyCode.Comma, ","), new KeyDef(KeyCode.Period, "."), - new KeyDef(KeyCode.Backslash, "/"), + new KeyDef(KeyCode.Slash, "/"), new KeyDef(KeyCode.RightShift, "Shift"), }, bottomRow, diff --git a/Modules/ShortcutManagerEditor/ShortcutProfileStore.cs b/Modules/ShortcutManagerEditor/ShortcutProfileStore.cs index 76cc18b41e..eee8af40b9 100644 --- a/Modules/ShortcutManagerEditor/ShortcutProfileStore.cs +++ b/Modules/ShortcutManagerEditor/ShortcutProfileStore.cs @@ -92,6 +92,26 @@ static string GetPathForProfile(string id) static IEnumerable GetAllShortcutProfilePaths() { var shortcutsFolderPath = GetShortcutFolderPath(); + if (ModeService.currentId == ModeService.k_DefaultModeId) + { + var legacyShortcutFolder = Paths.Combine(InternalEditorUtility.unityPreferencesFolder, "shortcuts"); + if (System.IO.Directory.Exists(legacyShortcutFolder)) + { + var legacyShortcutFiles = System.IO.Directory.GetFiles(legacyShortcutFolder, "*.shortcut", System.IO.SearchOption.TopDirectoryOnly).ToArray(); + if (legacyShortcutFiles.Length > 0 && !System.IO.Directory.Exists(shortcutsFolderPath)) + System.IO.Directory.CreateDirectory(shortcutsFolderPath); + foreach (var shortcutPath in legacyShortcutFiles) + { + var fileName = Path.GetFileName(shortcutPath); + var dst = Path.Combine(shortcutsFolderPath, fileName); + if (!File.Exists(dst)) + { + FileUtil.CopyFileIfExists(shortcutPath, dst, false); + } + } + } + } + if (!System.IO.Directory.Exists(shortcutsFolderPath)) return Enumerable.Empty(); diff --git a/Modules/SketchUpEditor/Mono/SketchUpImporterModelEditor.cs b/Modules/SketchUpEditor/Mono/SketchUpImporterModelEditor.cs index e8c50d13e0..1f09047d42 100644 --- a/Modules/SketchUpEditor/Mono/SketchUpImporterModelEditor.cs +++ b/Modules/SketchUpEditor/Mono/SketchUpImporterModelEditor.cs @@ -177,7 +177,7 @@ public void SetSelectedNodes(int[] selectedNodes) static public readonly GUIContent fileUnitLabel = EditorGUIUtility.TrTextContent("Unit conversion", "Length measurement to unit conversion. The value in Scale Factor is calculated based on the value here"); static public readonly GUIContent longitudeLabel = EditorGUIUtility.TrTextContent("Longitude", "Longitude Geo-location"); static public readonly GUIContent latitudeLabel = EditorGUIUtility.TrTextContent("Latitude", "Latitude Geo-location"); - static public readonly GUIContent northCorrectionLabel = EditorGUIUtility.TrTextContent("North Correction", "The angle which will rotate the north direction to the z-axis for a the model"); + static public readonly GUIContent northCorrectionLabel = EditorGUIUtility.TrTextContent("North Correction", "The angle which will rotate the north direction to the z-axis for the model"); static public readonly GUIContent[] measurementOptions = { EditorGUIUtility.TrTextContent("Meters"), diff --git a/Modules/SpriteShapeEditor/Managed/SpriteShapeRendererEditor.cs b/Modules/SpriteShapeEditor/Managed/SpriteShapeRendererEditor.cs index 4a02cd2f5c..9af3c63a4f 100644 --- a/Modules/SpriteShapeEditor/Managed/SpriteShapeRendererEditor.cs +++ b/Modules/SpriteShapeEditor/Managed/SpriteShapeRendererEditor.cs @@ -19,9 +19,13 @@ internal class SpriteShapeRendererInspector : RendererEditorBase private static class Styles { - public static readonly GUIContent materialLabel = EditorGUIUtility.TrTextContent("Material", "Material to be used by SpriteRenderer"); + public static readonly GUIContent fillMaterialLabel = EditorGUIUtility.TrTextContent("Fill Material", "Fill Material to be used by SpriteShapeRenderer"); + public static readonly GUIContent edgeMaterialLabel = EditorGUIUtility.TrTextContent("Edge Material", "Edge Material to be used by SpriteShapeRenderer"); public static readonly GUIContent colorLabel = EditorGUIUtility.TrTextContent("Color", "Rendering color for the Sprite graphic"); public static readonly Texture2D warningIcon = EditorGUIUtility.LoadIcon("console.warnicon"); + + public static readonly string mainTexErrorText = L10n.Tr("Material does not have a _MainTex texture property. It is required for SpriteShapeRenderer."); + public static readonly string offsetScaleErrorText = L10n.Tr("Material texture property _MainTex has offset/scale set. It is incompatible with SpriteShapeRenderer."); } public override void OnEnable() @@ -42,29 +46,16 @@ public override void OnInspectorGUI() EditorGUILayout.PropertyField(m_Color, Styles.colorLabel, true); EditorGUILayout.PropertyField(m_MaskInteraction); - if (m_Material.arraySize == 0) - m_Material.InsertArrayElementAtIndex(0); - - Rect r = GUILayoutUtility.GetRect( - EditorGUILayout.kLabelFloatMinW, EditorGUILayout.kLabelFloatMaxW, - EditorGUI.kSingleLineHeight, EditorGUI.kSingleLineHeight); - - EditorGUI.showMixedValue = m_Material.hasMultipleDifferentValues; - Object currentMaterialRef = m_Material.GetArrayElementAtIndex(0).objectReferenceValue; - Object returnedMaterialRef = EditorGUI.ObjectField(r, Styles.materialLabel, currentMaterialRef, typeof(Material), false); - if (returnedMaterialRef != currentMaterialRef) - { - m_Material.GetArrayElementAtIndex(0).objectReferenceValue = returnedMaterialRef; - } - EditorGUI.showMixedValue = false; + EditorGUILayout.PropertyField(m_Material.GetArrayElementAtIndex(0), Styles.fillMaterialLabel, true); + EditorGUILayout.PropertyField(m_Material.GetArrayElementAtIndex(1), Styles.edgeMaterialLabel, true); bool isTextureTiled; - if (!DoesMaterialHaveSpriteTexture(out isTextureTiled)) - ShowError("Material does not have a _MainTex texture property. It is required for SpriteRenderer."); + if (!DoesFillMaterialHaveSpriteTexture(out isTextureTiled)) + ShowError(Styles.mainTexErrorText); else { if (isTextureTiled) - ShowError("Material texture property _MainTex has offset/scale set. It is incompatible with SpriteRenderer."); + ShowError(Styles.offsetScaleErrorText); } Other2DSettingsGUI(); @@ -72,7 +63,7 @@ public override void OnInspectorGUI() serializedObject.ApplyModifiedProperties(); } - private bool DoesMaterialHaveSpriteTexture(out bool tiled) + private bool DoesFillMaterialHaveSpriteTexture(out bool tiled) { tiled = false; diff --git a/Modules/StyleSheetsEditor/StyleCatalog.cs b/Modules/StyleSheetsEditor/StyleCatalog.cs index d93701778b..cf41f74f40 100644 --- a/Modules/StyleSheetsEditor/StyleCatalog.cs +++ b/Modules/StyleSheetsEditor/StyleCatalog.cs @@ -551,29 +551,75 @@ public T GetResource(string key, T defaultValue = null) where T : UnityEngine return GetResource(key.GetHashCode(), defaultValue); } - public Texture2D GetTexture(int key, bool autoScale = false) + static class TexturesByDPIScale { - var resourcePath = GetText(key); - if (String.IsNullOrEmpty(resourcePath)) - return null; + private static Dictionary> s_TexturesByDPIScale = new Dictionary>(); - float systemScale = GUIUtility.pixelsPerPoint; - if (autoScale && systemScale > 1f) + static TexturesByDPIScale() { + for (int i = 1; i < 4; ++i) + s_TexturesByDPIScale[i] = new Dictionary(); + } + + public static Texture2D GetTextureByDPIScale(string resourcePath, bool autoScale, float systemScale) + { + Texture2D tex = null; int scale = Mathf.RoundToInt(systemScale); - string dirName = Path.GetDirectoryName(resourcePath).Replace('\\', '/'); - string fileName = Path.GetFileNameWithoutExtension(resourcePath); - string fileExt = Path.GetExtension(resourcePath); - for (int s = scale; scale > 1; --scale) + + if (autoScale && systemScale > 1f) + { + if (TryGetTexture(scale, resourcePath, out tex)) + return tex; + + string dirName = Path.GetDirectoryName(resourcePath).Replace('\\', '/'); + string fileName = Path.GetFileNameWithoutExtension(resourcePath); + string fileExt = Path.GetExtension(resourcePath); + for (int s = scale; scale > 1; --scale) + { + string scaledResourcePath = $"{dirName}/{fileName}@{s}x{fileExt}"; + var scaledResource = StoreTextureByScale(scale, scaledResourcePath, resourcePath, false); + if (scaledResource != null) + return scaledResource; + } + } + + if (TryGetTexture(scale, resourcePath, out tex)) + return tex; + return StoreTextureByScale(scale, resourcePath, resourcePath, true); + } + + private static Texture2D StoreTextureByScale(int scale, string scaledPath, string resourcePath, bool logError) + { + var tex = EditorResources.Load(scaledPath, false); + if (tex) + { + if (!s_TexturesByDPIScale.ContainsKey(scale)) + s_TexturesByDPIScale[scale] = new Dictionary(); + s_TexturesByDPIScale[scale][resourcePath] = tex; + } + else if (logError) { - string scaledResourcePath = $"{dirName}/{fileName}@{s}x{fileExt}"; - var scaledResource = EditorResources.Load(scaledResourcePath, false); - if (scaledResource != null) - return scaledResource; + Debug.LogFormat(LogType.Warning, LogOption.NoStacktrace, null, $"Failed to store {resourcePath} > {scaledPath}"); } + return tex; + } + + private static bool TryGetTexture(int scale, string path, out Texture2D tex) + { + tex = null; + if (s_TexturesByDPIScale.ContainsKey(scale) && s_TexturesByDPIScale[scale].TryGetValue(path, out tex) && tex != null) + return true; + return false; } + } + + public Texture2D GetTexture(int key, bool autoScale = false) + { + var resourcePath = GetText(key); + if (String.IsNullOrEmpty(resourcePath)) + return null; - return EditorResources.Load(resourcePath, false); + return TexturesByDPIScale.GetTextureByDPIScale(resourcePath, autoScale, GUIUtility.pixelsPerPoint); } public Texture2D GetTexture(string key) diff --git a/Modules/StyleSheetsEditor/StyleSheetImporterImpl.cs b/Modules/StyleSheetsEditor/StyleSheetImporterImpl.cs index 22d68dcfc8..43da6278e2 100644 --- a/Modules/StyleSheetsEditor/StyleSheetImporterImpl.cs +++ b/Modules/StyleSheetsEditor/StyleSheetImporterImpl.cs @@ -124,7 +124,7 @@ protected void VisitUrlFunction(PrimitiveTerm term) return; } - string projectRelativePath = absoluteUri.AbsolutePath; + string projectRelativePath = absoluteUri.LocalPath; // Remove any leading "/" as this now used as a path relative to the current directory if (projectRelativePath.StartsWith("/")) diff --git a/Modules/Terrain/Public/PaintContext.cs b/Modules/Terrain/Public/PaintContext.cs index 395d9af732..84d7028285 100644 --- a/Modules/Terrain/Public/PaintContext.cs +++ b/Modules/Terrain/Public/PaintContext.cs @@ -284,6 +284,11 @@ public void ScatterHeightmap(string editorUndoName) public void GatherNormals() { RenderTexture rt = originTerrain.normalmapTexture; + if (rt == null) + { + Debug.LogError("Terrain has no normal map. Enable instanced rendering to ensure availability of normals."); + return; + } Material blitMaterial = TerrainPaintUtility.GetBlitMaterial(); diff --git a/Modules/Terrain/Public/TerrainPaintUtility.cs b/Modules/Terrain/Public/TerrainPaintUtility.cs index 421178af85..e0675b32ec 100644 --- a/Modules/Terrain/Public/TerrainPaintUtility.cs +++ b/Modules/Terrain/Public/TerrainPaintUtility.cs @@ -154,6 +154,9 @@ public static void EndPaintHeightmap(PaintContext ctx, string editorUndoName) public static PaintContext CollectNormals(Terrain terrain, Rect boundsInTerrainSpace, int extraBorderPixels = 0) { + if (terrain.normalmapTexture == null) + return null; + int heightmapResolution = terrain.terrainData.heightmapResolution; PaintContext ctx = InitializePaintContext(terrain, heightmapResolution, heightmapResolution, Terrain.normalmapRenderTextureFormat, boundsInTerrainSpace, extraBorderPixels); ctx.GatherNormals(); diff --git a/Modules/TerrainEditor/Brush/BrushEditor.cs b/Modules/TerrainEditor/Brush/BrushEditor.cs index 8476e965ac..ef56f31fad 100644 --- a/Modules/TerrainEditor/Brush/BrushEditor.cs +++ b/Modules/TerrainEditor/Brush/BrushEditor.cs @@ -60,18 +60,21 @@ public override void OnInspectorGUI() serializedObject.Update(); EditorGUI.BeginChangeCheck(); + Texture2D origMask = (Texture2D)m_Mask.objectReferenceValue; Texture2D mask = (Texture2D)EditorGUILayout.ObjectField(Styles.maskTexture, - (Texture2D)m_Mask.objectReferenceValue, typeof(Texture2D), false); + origMask, typeof(Texture2D), false); if (mask == null) { mask = Brush.DefaultMask(); m_HasChanged = true; } + if (origMask != mask) + m_Mask.objectReferenceValue = mask; + float blackWhiteRemapMin = m_BlackWhiteRemapMin.floatValue; float blackWhiteRemapMax = m_BlackWhiteRemapMax.floatValue; - m_Mask.objectReferenceValue = mask; EditorGUILayout.MinMaxSlider(Styles.remap, ref blackWhiteRemapMin, ref blackWhiteRemapMax, 0.0f, 1.0f); EditorGUILayout.PropertyField(m_InvertRemapRange); EditorGUILayout.CurveField(m_Falloff, Color.white, new Rect(0, 0, 1, 1)); diff --git a/Modules/TerrainEditor/PaintTools/CreateTerrainTool.cs b/Modules/TerrainEditor/PaintTools/CreateTerrainTool.cs index 1072bd9b58..cd300e5d70 100644 --- a/Modules/TerrainEditor/PaintTools/CreateTerrainTool.cs +++ b/Modules/TerrainEditor/PaintTools/CreateTerrainTool.cs @@ -15,7 +15,7 @@ internal class CreateTerrainTool : TerrainPaintTool { private class Styles { - public GUIContent fillHeightmapUsingNeighbors = EditorGUIUtility.TrTextContent("Fill Heightmap Using Neighbors", "If selected, it will fill heightmap of the new terrain performing cross blend of heightmaps of it's neighbors."); + public GUIContent fillHeightmapUsingNeighbors = EditorGUIUtility.TrTextContent("Fill Heightmap Using Neighbors", "If selected, it will fill heightmap of the new terrain performing cross blend of heightmaps of its neighbors."); public GUIContent fillAddressMode = EditorGUIUtility.TrTextContent("Fill Heightmap Address Mode", "Type of the terrain's neighbors sampling address mode."); } @@ -136,7 +136,13 @@ Terrain CreateNeighbor(Terrain parent, Vector3 position) terrain.allowAutoConnect = parent.allowAutoConnect; string parentTerrainDataDir = Path.GetDirectoryName(AssetDatabase.GetAssetPath(parent.terrainData)); - AssetDatabase.CreateAsset(terrainData, Path.Combine(parentTerrainDataDir, "TerrainData_" + terrainData.name + ".asset")); + + var assetsToSave = new UnityEngine.Object[1 + terrainData.alphamapTextureCount]; + assetsToSave[0] = terrainData; + for (int i = 0; i < terrainData.alphamapTextureCount; ++i) + assetsToSave[i + 1] = terrainData.alphamapTextures[i]; + + AssetDatabase.CreateAssetFromObjects(assetsToSave, Path.Combine(parentTerrainDataDir, "TerrainData_" + terrainData.name + ".asset")); if (m_FillHeightmapUsingNeighbors) FillHeightmapUsingNeighbors(terrain); @@ -217,7 +223,8 @@ private bool RaycastTerrain(Terrain terrain, Ray mouseRay, out RaycastHit hit, o public override void OnSceneGUI(Terrain terrain, IOnSceneGUI editContext) { if ((Event.current.type == EventType.MouseUp || Event.current.type == EventType.MouseDown) && - (Event.current.button == 2 || Event.current.alt)) + (Event.current.button == 2 || Event.current.alt) + || terrain.terrainData == null) { return; } diff --git a/Modules/TerrainEditor/PaintTools/PaintHeightTool.cs b/Modules/TerrainEditor/PaintTools/PaintHeightTool.cs index c4c9d6424f..8de90caaee 100644 --- a/Modules/TerrainEditor/PaintTools/PaintHeightTool.cs +++ b/Modules/TerrainEditor/PaintTools/PaintHeightTool.cs @@ -14,7 +14,7 @@ internal class PaintHeightTool : TerrainPaintTool const string toolName = "Raise or Lower Terrain"; [FormerlyPrefKeyAs("Terrain/Raise Height", "f1")] - [Shortcut("Terrain/Raise or Lower Terrain", typeof(TerrainToolShortcutContext))] + [Shortcut("Terrain/Raise or Lower Terrain", typeof(TerrainToolShortcutContext), KeyCode.F1)] static void SelectShortcut(ShortcutArguments args) { TerrainToolShortcutContext context = (TerrainToolShortcutContext)args.context; diff --git a/Modules/TerrainEditor/PaintTools/PaintTextureTool.cs b/Modules/TerrainEditor/PaintTools/PaintTextureTool.cs index a95ef733a8..a433da041b 100644 --- a/Modules/TerrainEditor/PaintTools/PaintTextureTool.cs +++ b/Modules/TerrainEditor/PaintTools/PaintTextureTool.cs @@ -21,8 +21,11 @@ internal class PaintTextureTool : TerrainPaintTool [SerializeField] TerrainLayer m_SelectedTerrainLayer = null; + // Keep this separate from m_SelectedTerrainLayer so that it allows selecting null TerrainLayers (like those deleted from Assets). + private int m_SelectedTerrainLayerIndex = -1; + [FormerlyPrefKeyAs("Terrain/Texture Paint", "f4")] - [Shortcut("Terrain/Paint Texture", typeof(TerrainToolShortcutContext))] + [Shortcut("Terrain/Paint Texture", typeof(TerrainToolShortcutContext), KeyCode.F4)] static void SelectShortcut(ShortcutArguments args) { TerrainToolShortcutContext context = (TerrainToolShortcutContext)args.context; @@ -39,6 +42,11 @@ public override string GetDesc() return "Paints the selected material layer onto the terrain texture"; } + public override void OnEnterToolMode() + { + m_SelectedTerrainLayerIndex = -1; + } + public override bool OnPaint(Terrain terrain, IOnPaint editContext) { BrushTransform brushXform = TerrainPaintUtility.CalculateBrushTransform(terrain, editContext.uv, editContext.brushSize, 0.0f); @@ -91,16 +99,19 @@ public override void OnInspectorGUI(Terrain terrain, IOnInspectorGUI editContext EditorGUILayout.Space(); - int layerIndex = TerrainPaintUtility.FindTerrainLayerIndex(terrain, m_SelectedTerrainLayer); - layerIndex = TerrainLayerUtility.ShowTerrainLayersSelectionHelper(terrain, layerIndex); + if (m_SelectedTerrainLayerIndex == -1) + m_SelectedTerrainLayerIndex = TerrainPaintUtility.FindTerrainLayerIndex(terrain, m_SelectedTerrainLayer); + + m_SelectedTerrainLayerIndex = TerrainLayerUtility.ShowTerrainLayersSelectionHelper(terrain, m_SelectedTerrainLayerIndex); EditorGUILayout.Space(); if (EditorGUI.EndChangeCheck()) { - m_SelectedTerrainLayer = layerIndex != -1 ? terrain.terrainData.terrainLayers[layerIndex] : null; + m_SelectedTerrainLayer = m_SelectedTerrainLayerIndex != -1 ? terrain.terrainData.terrainLayers[m_SelectedTerrainLayerIndex] : null; Save(true); } + terrain.materialTemplate.SetFloat("_NumLayersCount", terrain.terrainData.terrainLayers.Length); TerrainLayerUtility.ShowTerrainLayerGUI(terrain, m_SelectedTerrainLayer, ref m_SelectedTerrainLayerInspector, (m_TemplateMaterialEditor as MaterialEditor)?.customShaderGUI as ITerrainLayerCustomUI); EditorGUILayout.Space(); diff --git a/Modules/TerrainEditor/PaintTools/SetHeightTool.cs b/Modules/TerrainEditor/PaintTools/SetHeightTool.cs index 525fce70d7..bf19c959fb 100644 --- a/Modules/TerrainEditor/PaintTools/SetHeightTool.cs +++ b/Modules/TerrainEditor/PaintTools/SetHeightTool.cs @@ -21,7 +21,7 @@ internal class SetHeightTool : TerrainPaintTool [SerializeField] [FormerlyPrefKeyAs("Terrain/Set Height", "f2")] - [Shortcut("Terrain/Set Height", typeof(TerrainToolShortcutContext))] + [Shortcut("Terrain/Set Height", typeof(TerrainToolShortcutContext), KeyCode.F2)] static void SelectShortcut(ShortcutArguments args) { TerrainToolShortcutContext context = (TerrainToolShortcutContext)args.context; diff --git a/Modules/TerrainEditor/PaintTools/SmoothHeightTool.cs b/Modules/TerrainEditor/PaintTools/SmoothHeightTool.cs index e76497d51b..d1f5be6bd3 100644 --- a/Modules/TerrainEditor/PaintTools/SmoothHeightTool.cs +++ b/Modules/TerrainEditor/PaintTools/SmoothHeightTool.cs @@ -33,7 +33,7 @@ private Styles GetStyles() } [FormerlyPrefKeyAs("Terrain/Smooth Height", "f3")] - [Shortcut("Terrain/Smooth Height", typeof(TerrainToolShortcutContext))] + [Shortcut("Terrain/Smooth Height", typeof(TerrainToolShortcutContext), KeyCode.F3)] static void SelectShortcut(ShortcutArguments args) { TerrainToolShortcutContext context = (TerrainToolShortcutContext)args.context; diff --git a/Modules/TerrainEditor/PaintTools/StampTool.cs b/Modules/TerrainEditor/PaintTools/StampTool.cs index f2d5ec7b5d..38040c40d0 100644 --- a/Modules/TerrainEditor/PaintTools/StampTool.cs +++ b/Modules/TerrainEditor/PaintTools/StampTool.cs @@ -20,7 +20,7 @@ internal class StampTool : TerrainPaintTool [SerializeField] float m_MaxBlendAdd = 0.0f; - [Shortcut("Terrain/Stamp Terrain", typeof(TerrainToolShortcutContext))] + [Shortcut("Terrain/Stamp Terrain", typeof(TerrainToolShortcutContext), KeyCode.F7)] static void SelectShortcut(ShortcutArguments args) { TerrainToolShortcutContext context = (TerrainToolShortcutContext)args.context; @@ -32,7 +32,7 @@ class Styles public readonly GUIContent description = EditorGUIUtility.TrTextContent("Left click to stamp the brush onto the terrain.\n\nHold control and mousewheel to adjust height.\nHold shift to invert the stamp."); public readonly GUIContent height = EditorGUIUtility.TrTextContent("Stamp Height", "You can set the Stamp Height manually or you can hold shift and mouse wheel on the terrain to adjust it."); public readonly GUIContent down = EditorGUIUtility.TrTextContent("Subtract", "Subtract the stamp from the terrain."); - public readonly GUIContent maxadd = EditorGUIUtility.TrTextContent("Max <--> Add", "Blend between adding the heights, and taking the maximum."); + public readonly GUIContent maxadd = EditorGUIUtility.TrTextContent("Max <--> Add", "Blend between adding the heights and taking the maximum."); } private static Styles m_styles; diff --git a/Modules/TerrainEditor/TerrainInspector.cs b/Modules/TerrainEditor/TerrainInspector.cs index 77d43f1bbe..7f1ef01e4b 100644 --- a/Modules/TerrainEditor/TerrainInspector.cs +++ b/Modules/TerrainEditor/TerrainInspector.cs @@ -78,7 +78,7 @@ class Styles public readonly GUIContent[] toolNames = { EditorGUIUtility.TrTextContent("Create Neighbor Terrains", "Click the edges to create neighbor terrains"), - EditorGUIUtility.TrTextContent("Paint Terrain", "Select a tool from the drop down list"), + EditorGUIUtility.TrTextContent("Paint Terrain", "Select a tool from the drop-down list"), EditorGUIUtility.TrTextContent("Paint Trees", "Click to paint trees.\n\nHold shift and click to erase trees.\n\nHold Ctrl and click to erase only trees of the selected type."), EditorGUIUtility.TrTextContent("Paint Details", "Click to paint details.\n\nHold shift and click to erase details.\n\nHold Ctrl and click to erase only details of the selected type."), EditorGUIUtility.TrTextContent("Terrain Settings") @@ -94,6 +94,7 @@ class Styles public readonly GUIContent assign = EditorGUIUtility.TrTextContent("Assign"); public readonly GUIContent duplicateTab = EditorGUIUtility.TrTextContent("NOTE: Inspector tab is a duplicate. Paint functionality disabled."); + public readonly GUIContent gles2NotSupported = EditorGUIUtility.TrTextContentWithIcon("Terrain editting is not supported in GLES2.", MessageType.Info); // Textures public readonly GUIContent terrainLayers = EditorGUIUtility.TrTextContent("Terrain Layers"); @@ -138,11 +139,11 @@ class Styles // Settings public readonly GUIContent basicTerrain = EditorGUIUtility.TrTextContent("Basic Terrain"); public readonly GUIContent groupingID = EditorGUIUtility.TrTextContent("Grouping ID", "Grouping ID for auto connection"); - public readonly GUIContent allowAutoConnect = EditorGUIUtility.TrTextContent("Auto Connect", "Allow the current terrain tile automatically connect to neighboring tiles sharing the same grouping ID."); + public readonly GUIContent allowAutoConnect = EditorGUIUtility.TrTextContent("Auto Connect", "Allow the current terrain tile to automatically connect to neighboring tiles sharing the same grouping ID."); public readonly GUIContent attemptReconnect = EditorGUIUtility.TrTextContent("Reconnect", "Will attempt to re-run auto connection"); public readonly GUIContent drawTerrain = EditorGUIUtility.TrTextContent("Draw", "Toggle the rendering of terrain"); public readonly GUIContent drawInstancedTerrain = EditorGUIUtility.TrTextContent("Draw Instanced" , "Toggle terrain instancing rendering"); - public readonly GUIContent pixelError = EditorGUIUtility.TrTextContent("Pixel Error", "The accuracy of the mapping between the terrain maps (heightmap, textures, etc) and the generated terrain; higher values indicate lower accuracy but lower rendering overhead."); + public readonly GUIContent pixelError = EditorGUIUtility.TrTextContent("Pixel Error", "The accuracy of the mapping between the terrain maps (heightmap, textures, etc.) and the generated terrain; higher values indicate lower accuracy but lower rendering overhead."); public readonly GUIContent baseMapDist = EditorGUIUtility.TrTextContent("Base Map Dist.", "The maximum distance at which terrain textures will be displayed at full resolution. Beyond this distance, a lower resolution composite image will be used for efficiency."); public readonly GUIContent castShadows = EditorGUIUtility.TrTextContent("Cast Shadows", "Does the terrain cast shadows?"); public readonly GUIContent material = EditorGUIUtility.TrTextContent("Material", "The material used to render the terrain. The shader used by the material will affect how the color channels of a terrain texture are interpreted."); @@ -174,8 +175,12 @@ static float ScaledSliderWithRounding(GUIContent content, float valueInPercent, { EditorGUI.BeginChangeCheck(); + minVal *= scale; + maxVal *= scale; + float v = Mathf.Round(valueInPercent * scale / precision) * precision; - v = EditorGUILayout.Slider(content, v, minVal * scale, maxVal * scale); + v = Mathf.Clamp(v, minVal, maxVal); // this keeps the slider knob from disappearing + v = EditorGUILayout.Slider(content, v, minVal, maxVal); if (EditorGUI.EndChangeCheck()) { @@ -331,14 +336,14 @@ private void SelectPaintTool(int index) } [FormerlyPrefKeyAs("Terrain/Tree Brush", "f5")] - [Shortcut("Terrain/Tree Brush", typeof(TerrainToolShortcutContext))] + [Shortcut("Terrain/Tree Brush", typeof(TerrainToolShortcutContext), KeyCode.F5)] static void SelectPlaceTreeTool(ShortcutArguments args) { ChangeTool(args, editor => editor.selectedTool = TerrainTool.PlaceTree); } [FormerlyPrefKeyAs("Terrain/Detail Brush", "f6")] - [Shortcut("Terrain/Detail Brush", typeof(TerrainToolShortcutContext))] + [Shortcut("Terrain/Detail Brush", typeof(TerrainToolShortcutContext), KeyCode.F6)] static void SelectPaintDetailTool(ShortcutArguments args) { ChangeTool(args, editor => editor.selectedTool = TerrainTool.PaintDetail); @@ -1803,28 +1808,36 @@ public override void OnInspectorGUI() EditorGUI.BeginDisabledGroup(s_activeTerrainInspector != GetInstanceID() || s_activeTerrainInspectorInstance != this); - // Show the master tool selector - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); // flexible space on either end centers the toolbar - GUI.changed = false; int tool = (int)selectedTool; - int newlySelectedTool = GUILayout.Toolbar(tool, styles.toolIcons, styles.command); - - if (newlySelectedTool != tool) + if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLES2) + { + EditorGUILayout.HelpBox(styles.gles2NotSupported); + tool = (int)TerrainTool.TerrainSettings; + } + else { - SetCurrentPaintToolInactive(); - selectedTool = (TerrainTool)newlySelectedTool; - SetCurrentPaintToolActive(); + // Show the master tool selector + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); // flexible space on either end centers the toolbar + GUI.changed = false; + int newlySelectedTool = GUILayout.Toolbar(tool, styles.toolIcons, styles.command); - // Need to repaint other terrain inspectors as their previously selected tool is now deselected. - InspectorWindow.RepaintAllInspectors(); + if (newlySelectedTool != tool) + { + SetCurrentPaintToolInactive(); + selectedTool = (TerrainTool)newlySelectedTool; + SetCurrentPaintToolActive(); - if (Toolbar.get != null) - Toolbar.get.Repaint(); - } + // Need to repaint other terrain inspectors as their previously selected tool is now deselected. + InspectorWindow.RepaintAllInspectors(); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); + if (Toolbar.get != null) + Toolbar.get.Repaint(); + } + + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + } if (tool != (int)TerrainTool.Paint) { @@ -1832,12 +1845,14 @@ public override void OnInspectorGUI() if (tool == (int)TerrainTool.CreateNeighbor) { GUILayout.Label(m_CreateTool.GetName()); - GUILayout.Label(m_CreateTool.GetDesc(), EditorStyles.wordWrappedMiniLabel); + if (!string.IsNullOrEmpty(m_CreateTool.GetDesc())) + GUILayout.Label(m_CreateTool.GetDesc(), EditorStyles.wordWrappedMiniLabel); } else if (tool > (int)TerrainTool.Paint && tool < styles.toolIcons.Length) { GUILayout.Label(styles.toolNames[tool].text); - GUILayout.Label(styles.toolNames[tool].tooltip, EditorStyles.wordWrappedMiniLabel); + if (!string.IsNullOrEmpty(styles.toolNames[tool].tooltip)) + GUILayout.Label(styles.toolNames[tool].tooltip, EditorStyles.wordWrappedMiniLabel); } else { diff --git a/Modules/TextCore/ScriptBindings/FontEngine.bindings.cs b/Modules/TextCore/ScriptBindings/FontEngine.bindings.cs index 232231531e..2588c5d666 100644 --- a/Modules/TextCore/ScriptBindings/FontEngine.bindings.cs +++ b/Modules/TextCore/ScriptBindings/FontEngine.bindings.cs @@ -6,6 +6,7 @@ using System.Runtime.InteropServices; using UnityEngine.Scripting; using UnityEngine.Bindings; +using UnityEngine.Profiling; namespace UnityEngine.TextCore.LowLevel { @@ -135,7 +136,8 @@ public sealed class FontEngine { private static readonly FontEngine s_Instance = new FontEngine(); - private static uint[] s_GlyphIndexes_MarshallingArray; + private static Glyph[] s_Glyphs = new Glyph[16]; + private static uint[] s_GlyphIndexes_MarshallingArray = new uint[16]; private static GlyphMarshallingStruct[] s_GlyphMarshallingStruct_IN = new GlyphMarshallingStruct[16]; private static GlyphMarshallingStruct[] s_GlyphMarshallingStruct_OUT = new GlyphMarshallingStruct[16]; @@ -143,7 +145,6 @@ public sealed class FontEngine private static GlyphRect[] s_FreeGlyphRects = new GlyphRect[16]; private static GlyphRect[] s_UsedGlyphRects = new GlyphRect[16]; - private static Glyph[] s_Glyphs = new Glyph[16]; private static GlyphPairAdjustmentRecord[] s_PairAdjustmentRecords_MarshallingArray; private static Dictionary s_GlyphLookupDictionary = new Dictionary(); @@ -815,10 +816,15 @@ extern static bool TryAddGlyphToTexture_Internal(uint glyphIndex, int padding, /// internal static bool TryAddGlyphsToTexture(List glyphIndexes, int padding, GlyphPackingMode packingMode, List freeGlyphRects, List usedGlyphRects, GlyphRenderMode renderMode, Texture2D texture, out Glyph[] glyphs) { + Profiler.BeginSample("FontEngine.TryAddGlyphsToTexture"); + glyphs = null; if (glyphIndexes == null || glyphIndexes.Count == 0) + { + Profiler.EndSample(); return false; + } int glyphCount = glyphIndexes.Count; @@ -854,8 +860,10 @@ internal static bool TryAddGlyphsToTexture(List glyphIndexes, int padding, s_GlyphMarshallingStruct_OUT = new GlyphMarshallingStruct[newSize]; } - // Copy glyph indexes and glyph rect data to marshalling arrays. - int glyphRectCount = Mathf.Max(freeGlyphRectCount, usedGlyphRectCount, glyphCount); + // Determine the max count + int glyphRectCount = FontEngineUtilities.MaxValue(freeGlyphRectCount, usedGlyphRectCount, glyphCount); + + // Copy inbound data to Marshalling arrays. for (int i = 0; i < glyphRectCount; i++) { if (i < glyphCount) @@ -880,8 +888,10 @@ internal static bool TryAddGlyphsToTexture(List glyphIndexes, int padding, freeGlyphRects.Clear(); usedGlyphRects.Clear(); - // Copy marshalled free and used GlyphRect data over. - glyphRectCount = Mathf.Max(freeGlyphRectCount, usedGlyphRectCount, glyphCount); + // Determine the max count + glyphRectCount = FontEngineUtilities.MaxValue(freeGlyphRectCount, usedGlyphRectCount, glyphCount); + + // Copy marshalled data back to their appropriate data structures. for (int i = 0; i < glyphRectCount; i++) { if (i < glyphCount) @@ -896,6 +906,8 @@ internal static bool TryAddGlyphsToTexture(List glyphIndexes, int padding, glyphs = s_Glyphs; + Profiler.EndSample(); + return allGlyphsAdded; } @@ -1108,5 +1120,10 @@ internal static bool Approximately(float a, float b) { return Mathf.Abs(a - b) < 0.001f; } + + internal static int MaxValue(int a, int b, int c) + { + return a < b ? (b < c ? c : b) : (a < c ? c : a); + } } } diff --git a/Modules/TextRendering/TextRendering.bindings.cs b/Modules/TextRendering/TextRendering.bindings.cs index d2d1875ef8..ee3dfb2897 100644 --- a/Modules/TextRendering/TextRendering.bindings.cs +++ b/Modules/TextRendering/TextRendering.bindings.cs @@ -334,7 +334,13 @@ public Font() public Font(string name) { - Internal_CreateFont(this, name); + // Determine if string name contains the name of the font file or the path to the font file. + bool isFileName = System.IO.Path.GetDirectoryName(name) == string.Empty; + + if (isFileName) + Internal_CreateFont(this, name); + else + Internal_CreateFontFromPath(this, name); } private Font(string[] names, int size) @@ -374,8 +380,10 @@ public bool HasCharacter(char c) private extern bool HasCharacter(int c); public static extern string[] GetOSInstalledFontNames(); + public static extern string[] GetPathsToOSFonts(); private static extern void Internal_CreateFont([Writable] Font self, string name); + private static extern void Internal_CreateFontFromPath([Writable] Font self, string fontPath); private static extern void Internal_CreateDynamicFont([Writable] Font self, string[] _names, int size); [FreeFunction("TextRenderingPrivate::GetCharacterInfo", HasExplicitThis = true)] diff --git a/Modules/Tilemap/ScriptBindings/Tilemap.bindings.cs b/Modules/Tilemap/ScriptBindings/Tilemap.bindings.cs index c683a3f831..82b31e519f 100644 --- a/Modules/Tilemap/ScriptBindings/Tilemap.bindings.cs +++ b/Modules/Tilemap/ScriptBindings/Tilemap.bindings.cs @@ -114,7 +114,7 @@ public extern Matrix4x4 orientationMatrix } internal extern Object GetTileAsset(Vector3Int position); - public TileBase GetTile(Vector3Int position) { return (TileBase)GetTileAsset(position); } + public TileBase GetTile(Vector3Int position) { return GetTileAsset(position) as TileBase; } public T GetTile(Vector3Int position) where T : TileBase { return GetTileAsset(position) as T; } internal extern Object[] GetTileAssetsBlock(Vector3Int position, Vector3Int blockDimensions); @@ -412,5 +412,11 @@ public extern uint maximumTileChangeCount get; set; } + + public extern float extrusionFactor + { + get; + set; + } } } diff --git a/Modules/TilemapEditor/Editor/Managed/Grid/GridPalette.cs b/Modules/TilemapEditor/Editor/Managed/Grid/GridPalette.cs new file mode 100644 index 0000000000..ec7eecb783 --- /dev/null +++ b/Modules/TilemapEditor/Editor/Managed/Grid/GridPalette.cs @@ -0,0 +1,25 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using UnityEngine; + +namespace UnityEditor +{ + /// GridPalette stores settings for Palette assets when shown in the Palette window. + public class GridPalette : ScriptableObject + { + /// Controls the sizing of cells for a Palette. + public enum CellSizing + { + /// Automatically resizes the Palette cells by the size of Sprites in the Palette. + Automatic = 0, + /// Size of Palette cells will be changed manually by the user. + Manual = 100 + } + + /// Determines the sizing of cells for a Palette. + [SerializeField] + public CellSizing cellSizing; + } +} diff --git a/Modules/TilemapEditor/Editor/Managed/TilemapCollider2DEditor.cs b/Modules/TilemapEditor/Editor/Managed/TilemapCollider2DEditor.cs index 7c925dc6bf..6f262cb83d 100644 --- a/Modules/TilemapEditor/Editor/Managed/TilemapCollider2DEditor.cs +++ b/Modules/TilemapEditor/Editor/Managed/TilemapCollider2DEditor.cs @@ -12,24 +12,31 @@ namespace UnityEditor internal class TilemapCollider2DEditor : Collider2DEditorBase { private SerializedProperty m_MaximumTileChangeCount; + private SerializedProperty m_ExtrusionFactor; private new static class Styles { public static readonly GUIContent maximumTileChangeCountLabel = EditorGUIUtility.TrTextContent("Max Tile Change Count" , "Maximum number of Tile Changes accumulated before doing a full collider rebuild instead of an incremental rebuild. " + "Change this if incremental rebuilds are slow for the number of Tile Changes accumulated."); + public static readonly GUIContent extrusionFactorLabel = EditorGUIUtility.TrTextContent("Extrusion Factor" + , "Extrudes collider shape of each Tile by this amount for helping with compositing fine gaps between " + + "neighboring Tile's collider shape when using a CompositeCollider2D. This is in Unity world-space units."); } public override void OnEnable() { base.OnEnable(); m_MaximumTileChangeCount = serializedObject.FindProperty("m_MaximumTileChangeCount"); + m_ExtrusionFactor = serializedObject.FindProperty("m_ExtrusionFactor"); } public override void OnInspectorGUI() { serializedObject.Update(); EditorGUILayout.PropertyField(m_MaximumTileChangeCount, Styles.maximumTileChangeCountLabel); + using (new EditorGUI.DisabledScope(!(target as TilemapCollider2D).usedByComposite)) + EditorGUILayout.PropertyField(m_ExtrusionFactor, Styles.extrusionFactorLabel); base.OnInspectorGUI(); serializedObject.ApplyModifiedProperties(); diff --git a/Modules/TreeEditor/TreeEditor.cs b/Modules/TreeEditor/TreeEditor.cs index 8ee5d00614..d1fe0f0a0a 100644 --- a/Modules/TreeEditor/TreeEditor.cs +++ b/Modules/TreeEditor/TreeEditor.cs @@ -163,9 +163,9 @@ public enum EditMode private static string weldLengthString = L10n.Tr("Weld Length|Defines how far up the branch the weld spread starts."); - private static string spreadTopString = L10n.Tr("Spread Top|Weld's spread factor on the top-side of the branch, relative to it's parent branch. Zero means no spread."); + private static string spreadTopString = L10n.Tr("Spread Top|Weld's spread factor on the top-side of the branch, relative to its parent branch. Zero means no spread."); - private static string spreadBottomString = L10n.Tr("Spread Bottom|Weld's spread factor on the bottom-side of the branch, relative to it's parent branch. Zero means no spread."); + private static string spreadBottomString = L10n.Tr("Spread Bottom|Weld's spread factor on the bottom-side of the branch, relative to its parent branch. Zero means no spread."); private static string breakChanceString = L10n.Tr("Break Chance|Chance of a branch breaking, i.e. 0 = no branches are broken, 0.5 = half of the branches are broken, 1.0 = all the branches are broken."); @@ -503,8 +503,6 @@ void SelectGroup(TreeGroup group) s_SelectedNode = null; s_SelectedPoint = -1; - EditorUtility.SetDirty(target); - Tree tree = target as Tree; if (tree == null) return; Renderer treeRenderer = tree.GetComponent(); @@ -2558,7 +2556,7 @@ void DrawHierachy(TreeData treeData, Renderer renderer, Rect sizeRect) int ms = renderer.sharedMaterials.Length; Rect labelrect = new Rect(hierachyDisplayRect.xMax - 80 - 4, hierachyDisplayRect.yMax + offset.y - 40 - 4, 80, 40); - string text = TreeEditorHelper.GetGUIContent("Hierachy Stats").text; + string text = TreeEditorHelper.GetGUIContent("Hierarchy Stats").text; text = text.Replace("[v]", vs.ToString()); text = text.Replace("[t]", ts.ToString()); text = text.Replace("[m]", ms.ToString()); diff --git a/Modules/UIElements/Foldout.cs b/Modules/UIElements/Foldout.cs index 996f9ca7fc..e201728c72 100644 --- a/Modules/UIElements/Foldout.cs +++ b/Modules/UIElements/Foldout.cs @@ -11,6 +11,24 @@ public class Foldout : BindableElement, INotifyValueChanged public new class UxmlFactory : UxmlFactory {} + public new class UxmlTraits : BindableElement.UxmlTraits + { + UxmlStringAttributeDescription m_Text = new UxmlStringAttributeDescription { name = "text" }; + UxmlBoolAttributeDescription m_Value = new UxmlBoolAttributeDescription { name = "value" }; + + public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) + { + base.Init(ve, bag, cc); + + Foldout f = ve as Foldout; + if (f != null) + { + f.text = m_Text.GetValueFromBag(bag, cc); + f.SetValueWithoutNotify(m_Value.GetValueFromBag(bag, cc)); + } + } + } + Toggle m_Toggle; VisualElement m_Container; @@ -34,7 +52,9 @@ public string text } } - private bool m_Value = true; + [SerializeField] + private bool m_Value; + public bool value { get @@ -51,6 +71,7 @@ public bool value evt.target = this; SetValueWithoutNotify(value); SendEvent(evt); + SaveViewData(); } } } @@ -66,8 +87,20 @@ public void SetValueWithoutNotify(bool newValue) public static readonly string toggleUssClassName = ussClassName + "__toggle"; public static readonly string contentUssClassName = ussClassName + "__content"; + internal override void OnViewDataReady() + { + base.OnViewDataReady(); + + string key = GetFullHierarchicalViewDataKey(); + + OverwriteFromViewData(this, key); + SetValueWithoutNotify(m_Value); + } + public Foldout() { + m_Value = true; + AddToClassList(ussClassName); m_Toggle = new Toggle diff --git a/Modules/UIElements/ListView.cs b/Modules/UIElements/ListView.cs index 2f5bc13dd8..2bffcda9ed 100644 --- a/Modules/UIElements/ListView.cs +++ b/Modules/UIElements/ListView.cs @@ -26,7 +26,11 @@ public override IEnumerable uxmlChildElementsDescri public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) { base.Init(ve, bag, cc); - ((ListView)ve).itemHeight = m_ItemHeight.GetValueFromBag(bag, cc); + int itemHeight = 0; + if (m_ItemHeight.TryGetValueFromBag(bag, cc, ref itemHeight)) + { + ((ListView)ve).itemHeight = itemHeight; + } } } diff --git a/Modules/UIElements/Panel.cs b/Modules/UIElements/Panel.cs index a2e09caae2..99db03b076 100644 --- a/Modules/UIElements/Panel.cs +++ b/Modules/UIElements/Panel.cs @@ -17,24 +17,26 @@ public enum ContextType [Flags] internal enum VersionChangeType { - //Some data was bound - Bindings = 1 << 8, + // Some data was bound + Bindings = 1 << 0, // persistent data ready - ViewData = 1 << 7, + ViewData = 1 << 1, // changes to hierarchy - Hierarchy = 1 << 6, - // changes to layout - Layout = 1 << 5, + Hierarchy = 1 << 2, + // changes to properties that may have an impact on layout + Layout = 1 << 3, // changes to StyleSheet, USS class StyleSheet = 1 << 4, // changes to styles, colors and other render properties - Styles = 1 << 3, - // transforms are invalid - Transform = 1 << 2, - // clips (rect position or size) are invalid - Clip = 1 << 1, - // pixels in the target have been changed, just repaint, only makes sense on the Panel - Repaint = 1 << 0, + Styles = 1 << 5, + Overflow = 1 << 6, + BorderRadius = 1 << 7, + // changes that may impact the world transform (e.g. laid out position, local transform) + Transform = 1 << 8, + // changes to the size of the element after layout has been performed, without taking the local transform into account + Size = 1 << 9, + // The visuals of the element have changed + Repaint = 1 << 10, } [Flags] @@ -209,15 +211,18 @@ internal void SetElementUnderMouse(VisualElement newElementUnderMouse, EventBase VisualElement previousTopElementUnderMouse = topElementUnderMouse; topElementUnderMouse = newElementUnderMouse; - if (triggerEvent == null) + IMouseEvent mouseEvent = triggerEvent == null ? null : triggerEvent as IMouseEvent; + var mousePosition = mouseEvent == null + ? MousePositionTracker.mousePosition + : mouseEvent?.mousePosition ?? Vector2.zero; + + // mouse enter/leave must be dispatched *any* time the element under mouse changes + using (new EventDispatcherGate(dispatcher)) { - using (new EventDispatcherGate(dispatcher)) - { - MouseEventsHelper.SendEnterLeave(previousTopElementUnderMouse, topElementUnderMouse, null, MousePositionTracker.mousePosition); - MouseEventsHelper.SendMouseOverMouseOut(previousTopElementUnderMouse, topElementUnderMouse, null, MousePositionTracker.mousePosition); - } + MouseEventsHelper.SendEnterLeave(previousTopElementUnderMouse, topElementUnderMouse, mouseEvent, mousePosition); } - else if ( + + if (triggerEvent == null || triggerEvent.eventTypeId == MouseMoveEvent.TypeId() || triggerEvent.eventTypeId == MouseDownEvent.TypeId() || triggerEvent.eventTypeId == MouseUpEvent.TypeId() || @@ -225,20 +230,17 @@ internal void SetElementUnderMouse(VisualElement newElementUnderMouse, EventBase triggerEvent.eventTypeId == MouseLeaveWindowEvent.TypeId() || triggerEvent.eventTypeId == WheelEvent.TypeId()) { - IMouseEvent mouseEvent = triggerEvent as IMouseEvent; using (new EventDispatcherGate(dispatcher)) { - MouseEventsHelper.SendEnterLeave(previousTopElementUnderMouse, topElementUnderMouse, mouseEvent, mouseEvent?.mousePosition ?? Vector2.zero); - MouseEventsHelper.SendMouseOverMouseOut(previousTopElementUnderMouse, topElementUnderMouse, mouseEvent, mouseEvent?.mousePosition ?? Vector2.zero); + MouseEventsHelper.SendMouseOverMouseOut(previousTopElementUnderMouse, topElementUnderMouse, mouseEvent, mousePosition); } } else if (triggerEvent.eventTypeId == DragUpdatedEvent.TypeId() || triggerEvent.eventTypeId == DragExitedEvent.TypeId()) { - IMouseEvent mouseEvent = triggerEvent as IMouseEvent; using (new EventDispatcherGate(dispatcher)) { - MouseEventsHelper.SendEnterLeave(previousTopElementUnderMouse, topElementUnderMouse, mouseEvent, mouseEvent?.mousePosition ?? Vector2.zero); + MouseEventsHelper.SendEnterLeave(previousTopElementUnderMouse, topElementUnderMouse, mouseEvent, mousePosition); } } } @@ -563,13 +565,24 @@ public override VisualElement Pick(Vector2 point) return PickAll(visualTree, point); } + private bool m_ValidatingLayout = false; public override void ValidateLayout() { - Profiler.BeginSample(m_ProfileLayoutName); - m_VisualTreeUpdater.UpdateVisualTreePhase(VisualTreeUpdatePhase.Styles); - m_VisualTreeUpdater.UpdateVisualTreePhase(VisualTreeUpdatePhase.Layout); - m_VisualTreeUpdater.UpdateVisualTreePhase(VisualTreeUpdatePhase.TransformClip); - Profiler.EndSample(); + // Reentrancy proofing: ValidateLayout() could be in the code path of updaters. + // Actual case: TransformClip update phase recomputes elements under mouse, which does a pick, which validates layout. + // Updaters use version numbers for early exit, but it may happen that an updater invalidates a subsequent updater. + if (!m_ValidatingLayout) + { + m_ValidatingLayout = true; + + Profiler.BeginSample(m_ProfileLayoutName); + m_VisualTreeUpdater.UpdateVisualTreePhase(VisualTreeUpdatePhase.Styles); + m_VisualTreeUpdater.UpdateVisualTreePhase(VisualTreeUpdatePhase.Layout); + m_VisualTreeUpdater.UpdateVisualTreePhase(VisualTreeUpdatePhase.TransformClip); + Profiler.EndSample(); + + m_ValidatingLayout = false; + } } public override void UpdateBindings() diff --git a/Modules/UIElements/Renderer/UIRChainBuilder.cs b/Modules/UIElements/Renderer/UIRChainBuilder.cs index 8350eab952..d0dbfb3059 100644 --- a/Modules/UIElements/Renderer/UIRChainBuilder.cs +++ b/Modules/UIElements/Renderer/UIRChainBuilder.cs @@ -26,8 +26,8 @@ internal class RenderChain : IDisposable { RenderChainCommand m_FirstCommand; uint m_DirtyID; // A monotonically increasing ID used to avoid double processing of some elements - VisualElement m_FirstDirtyVisuals, m_FirstDirtyTransform, m_FirstDirtyClipping; - VisualElement m_LastDirtyVisuals, m_LastDirtyTransform, m_LastDirtyClipping; + VisualElement m_FirstDirtyVisuals, m_FirstDirtyTransformOrSize, m_FirstDirtyClipping; + VisualElement m_LastDirtyVisuals, m_LastDirtyTransformOrSize, m_LastDirtyClipping; Pool m_CommandPool = new Pool(); ChainBuilderStats m_Stats; uint m_StatsElementsAdded, m_StatsElementsRemoved; @@ -139,13 +139,14 @@ public void Render(Rect topRect, Matrix4x4 projection) m_DirtyID++; + var clearDirty = ~(RenderDataDirtyTypes.Clipping | RenderDataDirtyTypes.ClippingHierarchy); VisualElement dirty = m_FirstDirtyClipping; s_ClipProcessingSampler.Begin(); while (dirty != null) { if (dirty.renderChainData.isInChain && dirty.renderChainData.dirtyID != m_DirtyID) Implementation.RenderEvents.ProcessOnClippingChanged(this, dirty, m_DirtyID, device, ref m_Stats); - dirty.renderChainData.dirtiedClipping = false; + dirty.renderChainData.dirtiedValues &= clearDirty; var old = dirty; dirty = dirty.renderChainData.nextDirtyClipping; old.renderChainData.nextDirtyClipping = null; @@ -154,28 +155,30 @@ public void Render(Rect topRect, Matrix4x4 projection) m_FirstDirtyClipping = m_LastDirtyClipping = null; m_DirtyID++; - dirty = m_FirstDirtyTransform; + clearDirty = ~(RenderDataDirtyTypes.Transform | RenderDataDirtyTypes.Size); + dirty = m_FirstDirtyTransformOrSize; s_TransformProcessingSampler.Begin(); while (dirty != null) { if (dirty.renderChainData.isInChain && dirty.renderChainData.dirtyID != m_DirtyID) - Implementation.RenderEvents.ProcessOnTransformChanged(this, dirty, m_DirtyID, device, ref m_Stats); - dirty.renderChainData.dirtiedTransform = false; + Implementation.RenderEvents.ProcessOnTransformOrSizeChanged(this, dirty, m_DirtyID, device, ref m_Stats); + dirty.renderChainData.dirtiedValues &= clearDirty; var old = dirty; - dirty = dirty.renderChainData.nextDirtyTransform; - old.renderChainData.nextDirtyTransform = null; + dirty = dirty.renderChainData.nextDirtyTransformOrSize; + old.renderChainData.nextDirtyTransformOrSize = null; } s_TransformProcessingSampler.End(); - m_FirstDirtyTransform = m_LastDirtyTransform = null; + m_FirstDirtyTransformOrSize = m_LastDirtyTransformOrSize = null; m_DirtyID++; + clearDirty = ~(RenderDataDirtyTypes.Visuals | RenderDataDirtyTypes.VisualsHierarchy); dirty = m_FirstDirtyVisuals; s_VisualsProcessingSampler.Begin(); while (dirty != null) { if (dirty.renderChainData.isInChain && dirty.renderChainData.dirtyID != m_DirtyID) Implementation.RenderEvents.ProcessOnVisualsChanged(this, dirty, m_DirtyID, ref m_Stats); - dirty.renderChainData.dirtiedVisuals = 0; + dirty.renderChainData.dirtiedValues &= clearDirty; var old = dirty; dirty = dirty.renderChainData.nextDirtyVisuals; old.renderChainData.nextDirtyVisuals = null; @@ -275,10 +278,10 @@ public void UIEOnChildRemoving(VisualElement ve) var removalInfo = new Implementation.RemovalInfo(); m_StatsElementsRemoved += Implementation.RenderEvents.OnChildRemoving(this, ve, ref removalInfo); Debug.Assert(!ve.renderChainData.isInChain); - CleanupDirtyLists(removalInfo.anyDirtiedClipping, removalInfo.anyDirtiedTransform, removalInfo.anyDirtiedVisuals); + CleanupDirtyLists(removalInfo.anyDirtiedClipping, removalInfo.anyDirtiedTransformOrSize, removalInfo.anyDirtiedVisuals); } - public void CleanupDirtyLists(bool cleanClipping, bool cleanTransform, bool cleanVisuals) + public void CleanupDirtyLists(bool cleanClipping, bool cleanTransformOrSize, bool cleanVisuals) { if (cleanClipping) { @@ -309,16 +312,16 @@ public void CleanupDirtyLists(bool cleanClipping, bool cleanTransform, bool clea m_LastDirtyClipping = last; } - if (cleanTransform) + if (cleanTransformOrSize) { // Reset transform. VisualElement first = null; VisualElement last = null; - VisualElement current = m_FirstDirtyTransform; + VisualElement current = m_FirstDirtyTransformOrSize; VisualElement next = null; while (current != null) { - next = current.renderChainData.nextDirtyTransform; + next = current.renderChainData.nextDirtyTransformOrSize; if (current.renderChainData.isInChain) { first = first ?? current; @@ -327,16 +330,16 @@ public void CleanupDirtyLists(bool cleanClipping, bool cleanTransform, bool clea else { if (last != null) - last.renderChainData.nextDirtyTransform = next; - current.renderChainData.nextDirtyTransform = null; + last.renderChainData.nextDirtyTransformOrSize = next; + current.renderChainData.nextDirtyTransformOrSize = null; } current = next; m_StatsTransformListCleanup++; } - m_FirstDirtyTransform = first; - m_LastDirtyTransform = last; + m_FirstDirtyTransformOrSize = first; + m_LastDirtyTransformOrSize = last; } if (cleanVisuals) @@ -369,8 +372,12 @@ public void CleanupDirtyLists(bool cleanClipping, bool cleanTransform, bool clea } } - public void UIEOnTransformChanged(VisualElement ve) { Implementation.RenderEvents.OnTransformChanged(this, ve); } - public void UIEOnClippingChanged(VisualElement ve) { Implementation.RenderEvents.OnClippingChanged(this, ve); } + public void UIEOnTransformOrSizeChanged(VisualElement ve, bool transformChanged, bool sizeChanged) + { + Implementation.RenderEvents.OnTransformOrSizeChanged(this, ve, transformChanged, sizeChanged); + } + + public void UIEOnClippingChanged(VisualElement ve, bool hierarchical) { Implementation.RenderEvents.OnClippingChanged(this, ve, hierarchical); } public void UIEOnVisualsChanged(VisualElement ve, bool hierarchical) { Implementation.RenderEvents.OnVisualsChanged(this, ve, hierarchical); } #endregion @@ -441,35 +448,64 @@ internal void OnGroupTransformElementChangedTransform(VisualElement ve) internal void OnVisualsChanged(VisualElement ve, bool hierarchical) { - ve.renderChainData.dirtiedVisuals = hierarchical ? (byte)2 : (byte)1; - if (m_LastDirtyVisuals != null) + RenderDataDirtyTypes current = ve.renderChainData.dirtiedValues; + bool isInList = (current & (RenderDataDirtyTypes.Visuals | RenderDataDirtyTypes.VisualsHierarchy)) != 0; + + current |= RenderDataDirtyTypes.Visuals; + if (hierarchical) + current |= RenderDataDirtyTypes.VisualsHierarchy; + ve.renderChainData.dirtiedValues = current; + + if (!isInList) { - m_LastDirtyVisuals.renderChainData.nextDirtyVisuals = ve; - m_LastDirtyVisuals = ve; + if (m_LastDirtyVisuals != null) + { + m_LastDirtyVisuals.renderChainData.nextDirtyVisuals = ve; + m_LastDirtyVisuals = ve; + } + else m_FirstDirtyVisuals = m_LastDirtyVisuals = ve; } - else m_FirstDirtyVisuals = m_LastDirtyVisuals = ve; } - internal void OnClippingChanged(VisualElement ve) + internal void OnClippingChanged(VisualElement ve, bool hierarchical) { - ve.renderChainData.dirtiedClipping = true; - if (m_LastDirtyClipping != null) + RenderDataDirtyTypes current = ve.renderChainData.dirtiedValues; + bool isInList = (current & (RenderDataDirtyTypes.Clipping | RenderDataDirtyTypes.ClippingHierarchy)) != 0; + + current |= RenderDataDirtyTypes.Clipping; + if (hierarchical) + current |= RenderDataDirtyTypes.ClippingHierarchy; + ve.renderChainData.dirtiedValues = current; + + if (!isInList) { - m_LastDirtyClipping.renderChainData.nextDirtyClipping = ve; - m_LastDirtyClipping = ve; + if (m_LastDirtyClipping != null) + { + m_LastDirtyClipping.renderChainData.nextDirtyClipping = ve; + m_LastDirtyClipping = ve; + } + else m_FirstDirtyClipping = m_LastDirtyClipping = ve; } - else m_FirstDirtyClipping = m_LastDirtyClipping = ve; } - internal void OnTransformChanged(VisualElement ve) + internal void OnTransformOrSizeChanged(VisualElement ve, bool transformChanged, bool sizeChanged) { - ve.renderChainData.dirtiedTransform = true; - if (m_LastDirtyTransform != null) + RenderDataDirtyTypes current = ve.renderChainData.dirtiedValues; + bool isInList = (current & (RenderDataDirtyTypes.Transform | RenderDataDirtyTypes.Size)) != 0; + + ve.renderChainData.dirtiedValues = current | + (transformChanged ? RenderDataDirtyTypes.Transform : RenderDataDirtyTypes.None) | + (sizeChanged ? RenderDataDirtyTypes.Size : RenderDataDirtyTypes.None); + + if (!isInList) { - m_LastDirtyTransform.renderChainData.nextDirtyTransform = ve; - m_LastDirtyTransform = ve; + if (m_LastDirtyTransformOrSize != null) + { + m_LastDirtyTransformOrSize.renderChainData.nextDirtyTransformOrSize = ve; + m_LastDirtyTransformOrSize = ve; + } + else m_FirstDirtyTransformOrSize = m_LastDirtyTransformOrSize = ve; } - else m_FirstDirtyTransform = m_LastDirtyTransform = ve; } internal void BeforeRenderDeviceRelease() @@ -591,17 +627,28 @@ static VisualElement GetFirstElementInPanel(VisualElement ve) } + [Flags] + internal enum RenderDataDirtyTypes + { + None = 0, + Transform = 1 << 0, + Size = 1 << 1, + Clipping = 1 << 2, // The clipping state of the VE needs to be reevaluated. + ClippingHierarchy = 1 << 3, // Same as above, but applies to all descendants too. + Visuals = 1 << 4, // The visuals of the VE need to be repainted. + VisualsHierarchy = 1 << 5 // Same as above, but applies to all descendants too. + } + internal struct RenderChainVEData { internal VisualElement prev, next; // This is a flattened view of the visual element hierarchy internal VisualElement groupTransformAncestor, boneTransformAncestor; - internal VisualElement nextDirtyVisuals, nextDirtyTransform, nextDirtyClipping; // Embedded linked list for dirty updates + internal VisualElement nextDirtyVisuals, nextDirtyTransformOrSize, nextDirtyClipping; // Embedded linked list for dirty updates internal RenderChainCommand firstCommand, lastCommand; // Sequential for the same owner internal RenderChainCommand firstClosingCommand, lastClosingCommand; // Optional, sequential for the same owner, the presence of closing commands requires starting commands too, otherwise certain optimizations will become invalid internal bool isInChain, isStencilClipped, isHierarchyHidden; internal bool usesText, usesAtlas, disableNudging; - internal byte dirtiedVisuals; // 0, 1 is for self, and 2 is hierarchical - internal bool dirtiedClipping, dirtiedTransform; + internal RenderDataDirtyTypes dirtiedValues; internal Implementation.ClipMethod clipMethod; internal MeshHandle data, closingData; internal Alloc transformID; diff --git a/Modules/UIElements/Renderer/UIRChainBuilderImpl.cs b/Modules/UIElements/Renderer/UIRChainBuilderImpl.cs index a37dd61a05..9076331a51 100644 --- a/Modules/UIElements/Renderer/UIRChainBuilderImpl.cs +++ b/Modules/UIElements/Renderer/UIRChainBuilderImpl.cs @@ -20,7 +20,7 @@ internal enum ClipMethod struct RemovalInfo { public bool anyDirtiedClipping; - public bool anyDirtiedTransform; + public bool anyDirtiedTransformOrSize; public bool anyDirtiedVisuals; } @@ -34,7 +34,7 @@ internal static void OnStandardShaderChanged(RenderChain renderChain, Shader sta internal static uint OnChildAdded(RenderChain renderChain, VisualElement parent, VisualElement ve, int index) { uint addedCount = DepthFirstOnChildAdded(renderChain, parent, ve, index, true); - OnClippingChanged(renderChain, ve); + OnClippingChanged(renderChain, ve, true); OnVisualsChanged(renderChain, ve, true); return addedCount; } @@ -48,7 +48,7 @@ internal static void OnChildrenReordered(RenderChain renderChain, VisualElement for (int i = 0; i < childrenCount; i++) DepthFirstOnChildAdded(renderChain, ve, ve.hierarchy[i], i, false); - OnClippingChanged(renderChain, ve); + OnClippingChanged(renderChain, ve, true); OnVisualsChanged(renderChain, ve, true); } @@ -60,25 +60,20 @@ internal static uint OnChildRemoving(RenderChain renderChain, VisualElement ve, //internal static void OnChildDestroyed(RenderChain renderChain, VisualElement ve) { } internal static void OnVisualsChanged(RenderChain renderChain, VisualElement ve, bool hierarchical) { - if (ve.renderChainData.isInChain && ve.renderChainData.dirtiedVisuals == 0) - { - if (ve.renderChainData.dirtiedVisuals == 0) - renderChain.OnVisualsChanged(ve, hierarchical); - else if (hierarchical) - ve.renderChainData.dirtiedVisuals = 2; - } + if (ve.renderChainData.isInChain) + renderChain.OnVisualsChanged(ve, hierarchical); } - internal static void OnClippingChanged(RenderChain renderChain, VisualElement ve) + internal static void OnClippingChanged(RenderChain renderChain, VisualElement ve, bool hierarchical) { - if (ve.renderChainData.isInChain && !ve.renderChainData.dirtiedClipping) - renderChain.OnClippingChanged(ve); + if (ve.renderChainData.isInChain) + renderChain.OnClippingChanged(ve, hierarchical); } - internal static void OnTransformChanged(RenderChain renderChain, VisualElement ve) + internal static void OnTransformOrSizeChanged(RenderChain renderChain, VisualElement ve, bool transformChanged, bool sizeChanged) { - if (ve.renderChainData.isInChain && !ve.renderChainData.dirtiedTransform) - renderChain.OnTransformChanged(ve); + if (ve.renderChainData.isInChain) + renderChain.OnTransformOrSizeChanged(ve, transformChanged, sizeChanged); } internal static void OnRestoreTransformIDs(VisualElement ve, UIRenderDevice device) @@ -113,18 +108,18 @@ internal static Shader ResolveShader(Shader shader) internal static void ProcessOnClippingChanged(RenderChain renderChain, VisualElement ve, uint dirtyID, UIRenderDevice device, ref ChainBuilderStats stats) { stats.recursiveClipUpdates++; - DepthFirstOnClippingChanged(renderChain, ve.hierarchy.parent, ve, dirtyID, false, device, ref stats); + DepthFirstOnClippingChanged(renderChain, ve.hierarchy.parent, ve, dirtyID, false, true, false, false, false, device, ref stats); } - internal static void ProcessOnTransformChanged(RenderChain renderChain, VisualElement ve, uint dirtyID, UIRenderDevice device, ref ChainBuilderStats stats) + internal static void ProcessOnTransformOrSizeChanged(RenderChain renderChain, VisualElement ve, uint dirtyID, UIRenderDevice device, ref ChainBuilderStats stats) { stats.recursiveTransformUpdates++; - DepthFirstOnTransformChanged(renderChain, ve.hierarchy.parent, ve, dirtyID, device, false, ref stats); + DepthFirstOnTransformOrSizeChanged(renderChain, ve.hierarchy.parent, ve, dirtyID, device, false, false, ref stats); } internal static void ProcessOnVisualsChanged(RenderChain renderChain, VisualElement ve, uint dirtyID, ref ChainBuilderStats stats) { - bool hierarchical = ve.renderChainData.dirtiedVisuals == 2; + bool hierarchical = (ve.renderChainData.dirtiedValues & RenderDataDirtyTypes.VisualsHierarchy) != 0; if (hierarchical) stats.recursiveVisualUpdates++; else stats.nonRecursiveVisualUpdates++; @@ -143,9 +138,12 @@ internal static void ProcessRegenText(RenderChain renderChain, VisualElement ve, static Matrix4x4 GetTransformIDTransformInfo(VisualElement ve) { Debug.Assert(ve.renderChainData.allocatedTransformID || (ve.renderHint & (RenderHint.GroupTransform)) != 0); + Matrix4x4 transform; if (ve.renderChainData.groupTransformAncestor != null) - return ve.renderChainData.groupTransformAncestor.worldTransform.inverse * ve.worldTransform; - return ve.worldTransform; + transform = ve.renderChainData.groupTransformAncestor.worldTransform.inverse * ve.worldTransform; + else transform = ve.worldTransform; + transform.m22 = transform.m33 = 1.0f; // Once world-space mode is introduced, this should become conditional + return transform; } static Vector4 GetTransformIDClipInfo(VisualElement ve) @@ -171,6 +169,7 @@ static void GetVerticesTransformInfo(VisualElement ve, out Matrix4x4 transform, else if (ve.renderChainData.groupTransformAncestor != null) transform = ve.renderChainData.groupTransformAncestor.worldTransform.inverse * ve.worldTransform; else transform = ve.worldTransform; + transform.m22 = transform.m33 = 1.0f; // Once world-space mode is introduced, this should become conditional transformID = ve.renderChainData.transformID.start; } @@ -251,95 +250,196 @@ static uint DepthFirstOnChildRemoving(RenderChain renderChain, VisualElement ve, renderChain.device.Free(ve.renderChainData.data); ve.renderChainData.data = null; } - if (ve.renderChainData.dirtiedClipping) + if ((ve.renderChainData.dirtiedValues & (RenderDataDirtyTypes.Clipping | RenderDataDirtyTypes.ClippingHierarchy)) != 0) removalInfo.anyDirtiedClipping = true; - if (ve.renderChainData.dirtiedTransform) - removalInfo.anyDirtiedTransform = true; - if (ve.renderChainData.dirtiedVisuals > 0) + if ((ve.renderChainData.dirtiedValues & (RenderDataDirtyTypes.Transform | RenderDataDirtyTypes.Size)) != 0) + removalInfo.anyDirtiedTransformOrSize = true; + if ((ve.renderChainData.dirtiedValues & (RenderDataDirtyTypes.Visuals | RenderDataDirtyTypes.VisualsHierarchy)) != 0) removalInfo.anyDirtiedVisuals = true; } return deepCount + 1; } - static void DepthFirstOnClippingChanged(RenderChain renderChain, VisualElement parent, VisualElement ve, uint dirtyID, bool evenIfUpToDate, UIRenderDevice device, ref ChainBuilderStats stats) + static void DepthFirstOnClippingChanged(RenderChain renderChain, + VisualElement parent, + VisualElement ve, + uint dirtyID, + bool hierarchical, // MUST be false on the root call. Indicates that ALL descendants MUST be processed. + bool isRootOfChange, // MUST be true on the root call. + bool isPendingHierarchicalRepaint, // MUST be false on the root call. + bool inheritedTransformIDChanged, // MUST be false on the root call. + bool inheritedStencilClippedChanged,// MUST be false on the root call. + UIRenderDevice device, + ref ChainBuilderStats stats) { bool upToDate = dirtyID == ve.renderChainData.dirtyID; - if (!evenIfUpToDate && upToDate) + if (upToDate && !inheritedTransformIDChanged && !inheritedStencilClippedChanged) return; - ve.renderChainData.dirtyID = dirtyID; // Prevent reprocessing of the same element in the same pass + ve.renderChainData.dirtyID = dirtyID; // Prevent reprocessing of the same element in the same pass stats.recursiveClipUpdatesExpanded++; - var newClipMethod = DetermineClipMethod(ve); - var oldTransformID = ve.renderChainData.transformID.start; - bool needsTransformID = NeedsTransformID(ve, newClipMethod); - if (needsTransformID) - { + // Despite an originally non-hierarchical processing, we may need to recurse to propagate some values. When + // doing so, we may update elements that required hierarchical processing. In this case, we need to set + // this flag because otherwise, their own individual processing may be skipped since the dirtyID has been set. + hierarchical |= (ve.renderChainData.dirtiedValues & RenderDataDirtyTypes.ClippingHierarchy) != 0; + + isPendingHierarchicalRepaint |= (ve.renderChainData.dirtiedValues & RenderDataDirtyTypes.VisualsHierarchy) != 0; + + // Internal operations (done in this call) to do: + bool mustUpdateTransformID = hierarchical || isRootOfChange || inheritedTransformIDChanged; + bool mustUpdateClippingMethod = hierarchical || isRootOfChange; + bool mustUpdateStencilClippedFlag = hierarchical || isRootOfChange || inheritedStencilClippedChanged; + + // External operations (done by recursion or postponed) to do: + bool mustRepaintThis = false; + bool mustRepaintHierarchy = false; + bool mustProcessSizeChange = false; + // mustRecurse implies recursing on all children, but doesn't force anything beyond them. + // hierarchical implies recursing on all descendants + // As a result, hierarchical implies mustRecurse + bool mustRecurse = hierarchical; + + // Update the clipping method. + ClipMethod oldClippingMethod = ve.renderChainData.clipMethod; + ClipMethod newClippingMethod = oldClippingMethod; + if (mustUpdateClippingMethod) + newClippingMethod = DetermineClipMethod(ve); + + // Update the transform ID. + Alloc oldTransformID = ve.renderChainData.transformID; + Alloc newTransformID = oldTransformID; + if (mustUpdateTransformID) + { + if (NeedsTransformID(ve, newClippingMethod)) + { + if (!ve.renderChainData.allocatedTransformID) + { + newTransformID = device.AllocateTransform(); + ve.renderChainData.transformID = newTransformID; + } + } + else + { + if (ve.renderChainData.allocatedTransformID) + { + device.Free(ve.renderChainData.transformID); + newTransformID = new Alloc(); + ve.renderChainData.transformID = newTransformID; + } + } + if (!ve.renderChainData.allocatedTransformID) { - var newTransformID = device.AllocateTransform(); - if (newTransformID.size > 0) + if (parent != null && (ve.renderHint & RenderHint.GroupTransform) == 0) + { + if (parent.renderChainData.allocatedTransformID) + ve.renderChainData.boneTransformAncestor = parent; + else + ve.renderChainData.boneTransformAncestor = parent.renderChainData.boneTransformAncestor; + + newTransformID = parent.renderChainData.transformID; + // Mark this allocation as not owned by us. Note that we are hijacking this field since it is + // actually unused in the case of transform ids. + newTransformID.shortLived = true; ve.renderChainData.transformID = newTransformID; + } + else + ve.renderChainData.boneTransformAncestor = null; } } - else if (ve.renderChainData.allocatedTransformID) - { - device.Free(ve.renderChainData.transformID); - ve.renderChainData.transformID = new Alloc(); - } - bool hasParent = parent != null; - if (!ve.renderChainData.allocatedTransformID) + if (!ve.renderChainData.allocatedTransformID && newClippingMethod == ClipMethod.ShaderDiscard) + // Fallback to scissoring since we couldn't allocate a transform ID + newClippingMethod = ClipMethod.Scissor; + + if (oldClippingMethod != newClippingMethod) { - if (hasParent && (ve.renderHint & RenderHint.GroupTransform) == 0) + ve.renderChainData.clipMethod = newClippingMethod; + + if (oldClippingMethod == ClipMethod.Stencil || newClippingMethod == ClipMethod.Stencil) { - if (parent.renderChainData.allocatedTransformID) - ve.renderChainData.boneTransformAncestor = parent; - else ve.renderChainData.boneTransformAncestor = parent.renderChainData.boneTransformAncestor; - ve.renderChainData.transformID = parent.renderChainData.transformID; - ve.renderChainData.transformID.shortLived = true; // Mark this allocation as not owned by us + mustUpdateStencilClippedFlag = true; + + // Proper winding order must be used. + mustRepaintHierarchy = true; } - else ve.renderChainData.boneTransformAncestor = null; - if (newClipMethod == ClipMethod.ShaderDiscard) - newClipMethod = ClipMethod.Scissor; // Fallback to scissoring since we couldn't allocate a transform ID + + if (oldClippingMethod == ClipMethod.Scissor || newClippingMethod == ClipMethod.Scissor) + // We need to add/remove scissor push/pop commands + mustRepaintThis = true; + + if (newClippingMethod == ClipMethod.ShaderDiscard || oldClippingMethod == ClipMethod.ShaderDiscard && ve.renderChainData.allocatedTransformID) + // We must update the clipping rects. + mustProcessSizeChange = true; } - else if (upToDate) + + bool transformIdChanged = false; + if (TransformIDHasChanged(oldTransformID, newTransformID)) { - Debug.Assert(ve.renderChainData.clipMethod != ClipMethod.Undetermined); - return; // We are up to date already and we allocate our own transformID, so no need to recurse + transformIdChanged = true; + + // Our children MUST update their render data transformIDs + mustRecurse = true; + + // Our children MUST update their vertex transformIDs + mustRepaintHierarchy = true; } - if (!evenIfUpToDate && (oldTransformID != ve.renderChainData.transformID.start)) + bool isStencilClippedChanged = false; + if (mustUpdateStencilClippedFlag) { - // Introduce a recursive paint if the transformID changes due to shader discards - evenIfUpToDate = true; // Our children MUST update their vertex transformIDs - RenderEvents.OnVisualsChanged(renderChain, ve, true); + bool oldStencilClipped = ve.renderChainData.isStencilClipped; + bool newStencilClipped = newClippingMethod == ClipMethod.Stencil || (parent != null && parent.renderChainData.isStencilClipped); + ve.renderChainData.isStencilClipped = newStencilClipped; + if (oldStencilClipped != newStencilClipped) + { + isStencilClippedChanged = true; + + // Our children MUST update their isStencilClipped flag + mustRecurse = true; + } } - if (newClipMethod != ve.renderChainData.clipMethod) + if ((mustRepaintThis || mustRepaintHierarchy) && !isPendingHierarchicalRepaint) { - // Introduce a recursive repaint to regen indices in proper winding order for children if was using or will be using stencil clipping - bool needRecursePaint = (newClipMethod == ClipMethod.Stencil) || (ve.renderChainData.clipMethod == ClipMethod.Stencil); - - ve.renderChainData.clipMethod = newClipMethod; - ve.renderChainData.isStencilClipped = (newClipMethod == ClipMethod.Stencil) || (hasParent && ve.hierarchy.parent.renderChainData.isStencilClipped); - if (needRecursePaint) - RenderEvents.OnVisualsChanged(renderChain, ve, true); + OnVisualsChanged(renderChain, ve, mustRepaintHierarchy); + isPendingHierarchicalRepaint = true; } - // Recurse on children - int childrenCount = ve.hierarchy.childCount; - for (int i = 0; i < childrenCount; i++) - DepthFirstOnClippingChanged(renderChain, ve, ve.hierarchy[i], dirtyID, evenIfUpToDate, device, ref stats); + if (mustProcessSizeChange) + OnTransformOrSizeChanged(renderChain, ve, false, true); + + if (mustRecurse) + { + int childrenCount = ve.hierarchy.childCount; + for (int i = 0; i < childrenCount; i++) + DepthFirstOnClippingChanged( + renderChain, + ve, + ve.hierarchy[i], + dirtyID, + // Having to recurse doesn't mean that we need to process ALL descendants. For example, the + // propagation of the transformId may stop if a group or a bone is encountered. + hierarchical, + false, + isPendingHierarchicalRepaint, + transformIdChanged, + isStencilClippedChanged, + device, + ref stats); + } } - static void DepthFirstOnTransformChanged(RenderChain renderChain, VisualElement parent, VisualElement ve, uint dirtyID, UIRenderDevice device, bool isAncestorOfChangeSkinned, ref ChainBuilderStats stats) + static void DepthFirstOnTransformOrSizeChanged(RenderChain renderChain, VisualElement parent, VisualElement ve, uint dirtyID, UIRenderDevice device, bool isAncestorOfChangeSkinned, bool transformChanged, ref ChainBuilderStats stats) { if (dirtyID == ve.renderChainData.dirtyID) return; stats.recursiveTransformUpdatesExpanded++; + transformChanged |= (ve.renderChainData.dirtiedValues & RenderDataDirtyTypes.Transform) != 0; + bool dirtyHasBeenResolved = true; if (ve.renderChainData.allocatedTransformID) { @@ -347,6 +447,10 @@ static void DepthFirstOnTransformChanged(RenderChain renderChain, VisualElement isAncestorOfChangeSkinned = true; stats.boneTransformed++; } + else if (!transformChanged) + { + // Only the clip info had to be updated, we can skip the other cases which are for transform changes only. + } else if ((ve.renderHint & RenderHint.GroupTransform) != 0) { stats.groupTransformElementsChanged++; @@ -358,7 +462,7 @@ static void DepthFirstOnTransformChanged(RenderChain renderChain, VisualElement dirtyHasBeenResolved = false; // We just skipped processing, if another later transform change is queued on this element this pass then we should still process it stats.skipTransformed++; } - else if ((ve.renderChainData.dirtiedVisuals == 0) && (ve.renderChainData.data != null)) + else if ((ve.renderChainData.dirtiedValues & (RenderDataDirtyTypes.Visuals | RenderDataDirtyTypes.VisualsHierarchy)) == 0 && (ve.renderChainData.data != null)) { // If a visual update will happen, then skip work here as the visual update will incorporate the transformed vertices if (!ve.renderChainData.disableNudging && NudgeVerticesToNewSpace(ve, device)) @@ -378,7 +482,7 @@ static void DepthFirstOnTransformChanged(RenderChain renderChain, VisualElement // Recurse on children int childrenCount = ve.hierarchy.childCount; for (int i = 0; i < childrenCount; i++) - DepthFirstOnTransformChanged(renderChain, ve, ve.hierarchy[i], dirtyID, device, isAncestorOfChangeSkinned, ref stats); + DepthFirstOnTransformOrSizeChanged(renderChain, ve, ve.hierarchy[i], dirtyID, device, isAncestorOfChangeSkinned, transformChanged, ref stats); } else renderChain.OnGroupTransformElementChangedTransform(ve); // Hack until UIE moves to TMP @@ -493,6 +597,19 @@ static bool NeedsTransformID(VisualElement ve, ClipMethod newClipMethod) return (ve.renderHint & RenderHint.GroupTransform) == 0 && ((newClipMethod == ClipMethod.ShaderDiscard) || ((ve.renderHint & RenderHint.BoneTransform) == RenderHint.BoneTransform)); } + // Indicates whether the transform id assigned to an element has changed. It does not care who the owner is. + static bool TransformIDHasChanged(Alloc before, Alloc after) + { + if (before.size == 0 && after.size == 0) + // Whatever start is, both are invalid allocations. + return false; + + if (before.size != after.size || before.start != after.start) + return true; + + return false; + } + internal static UIRStylePainter PaintElement(RenderChain renderChain, VisualElement ve, ref ChainBuilderStats stats) { if (IsElementSelfHidden(ve) || ve.renderChainData.isHierarchyHidden) @@ -1060,6 +1177,8 @@ static void ResetCommands(RenderChain renderChain, VisualElement ve) if (ve.renderChainData.firstClosingCommand != null) { + renderChain.OnRenderCommandRemoved(ve.renderChainData.firstClosingCommand, ve.renderChainData.lastClosingCommand); + var c = ve.renderChainData.firstClosingCommand; while (c != ve.renderChainData.lastClosingCommand) { diff --git a/Modules/UIElements/Renderer/UIRLayoutUpdater.cs b/Modules/UIElements/Renderer/UIRLayoutUpdater.cs index 9f30c8ee4a..ea7aa4eeb6 100644 --- a/Modules/UIElements/Renderer/UIRLayoutUpdater.cs +++ b/Modules/UIElements/Renderer/UIRLayoutUpdater.cs @@ -26,6 +26,13 @@ public override void OnVersionChanged(VisualElement ve, VersionChangeType versio if ((versionChangeType & (VersionChangeType.Layout | VersionChangeType.Hierarchy)) == 0) return; + // Yoga DOES NOT expect the node tree to mutate while layout is being computed. + // it could lead to crashes (EXC_BAD_ACCESS) + if ((versionChangeType & VersionChangeType.Hierarchy) != 0 && panel.duringLayoutPhase) + { + throw new InvalidOperationException("Hierarchy change detected while computing layout, this is not supported."); + } + var yogaNode = ve.yogaNode; if (yogaNode != null && yogaNode.IsMeasureDefined) { @@ -66,17 +73,23 @@ private void UpdateSubTree(VisualElement ve, int currentLayoutPass) Rect lastRect = ve.renderData.lastLayout; bool rectChanged = false; + VersionChangeType changeType = 0; + // If the last layout rect is different than the current one we must dirty transform on children if ((lastRect.width != yogaRect.width) || (lastRect.height != yogaRect.height)) { - ve.IncrementVersion(VersionChangeType.Clip | VersionChangeType.Repaint); // Layout change require a clip update + repaint + changeType |= VersionChangeType.Size | VersionChangeType.Repaint; rectChanged = true; } if (yogaRect.position != lastRect.position) { - ve.IncrementVersion(VersionChangeType.Transform); + changeType |= VersionChangeType.Transform; rectChanged = true; } + + if (changeType != 0) + ve.IncrementVersion(changeType); + ve.renderData.lastLayout = yogaRect; // ignore clean sub trees diff --git a/Modules/UIElements/Renderer/UIRRepaintUpdater.cs b/Modules/UIElements/Renderer/UIRRepaintUpdater.cs index 189c64072f..dc63c58305 100644 --- a/Modules/UIElements/Renderer/UIRRepaintUpdater.cs +++ b/Modules/UIElements/Renderer/UIRRepaintUpdater.cs @@ -33,8 +33,16 @@ public override void OnVersionChanged(VisualElement ve, VersionChangeType versio if (renderChain == null) return; - if ((versionChangeType & (VersionChangeType.Transform | VersionChangeType.Clip)) != 0) - renderChain.UIEOnTransformChanged(ve); + bool transformChanged = (versionChangeType & VersionChangeType.Transform) != 0; + bool sizeChanged = (versionChangeType & VersionChangeType.Size) != 0; + bool overflowChanged = (versionChangeType & VersionChangeType.Overflow) != 0; + bool borderRadiusChanged = (versionChangeType & VersionChangeType.BorderRadius) != 0; + + if (transformChanged || sizeChanged) + renderChain.UIEOnTransformOrSizeChanged(ve, transformChanged, sizeChanged); + + if (overflowChanged || borderRadiusChanged) + renderChain.UIEOnClippingChanged(ve, false); if ((versionChangeType & VersionChangeType.Repaint) != 0) renderChain.UIEOnVisualsChanged(ve, false); diff --git a/Modules/UIElements/Renderer/UIRUtility.cs b/Modules/UIElements/Renderer/UIRUtility.cs index 080028aa50..6535fb2d16 100644 --- a/Modules/UIElements/Renderer/UIRUtility.cs +++ b/Modules/UIElements/Renderer/UIRUtility.cs @@ -37,21 +37,5 @@ public static void Destroy(Object obj) else Object.DestroyImmediate(obj); } - - public static bool GetOpenGLCoreVersion(out int major, out int minor) - { - var version = SystemInfo.graphicsDeviceVersion; - var rx = new Regex(@"OpenGL( *)[0-9].[0-9]"); - var matches = rx.Matches(version); - if (matches.Count == 0) - { - major = minor = -1; - return false; - } - var match = matches[0].Value; - major = match[match.Length - 3] - '0'; - minor = match[match.Length - 1] - '0'; - return true; - } } } diff --git a/Modules/UIElements/Renderer/UIRenderer/UIRenderDevice.cs b/Modules/UIElements/Renderer/UIRenderer/UIRenderDevice.cs index 591dab3436..43fb65ac19 100644 --- a/Modules/UIElements/Renderer/UIRenderer/UIRenderDevice.cs +++ b/Modules/UIElements/Renderer/UIRenderer/UIRenderDevice.cs @@ -136,6 +136,10 @@ public void Dispose() static CustomSampler s_FenceSampler = CustomSampler.Create("UIR.WaitOnFence"); static CustomSampler s_BeforeDrawSampler = CustomSampler.Create("UIR.BeforeDraw"); + static bool? s_ComputeIsAvailable; + const string k_ComputeIsAvailableTag = "UIE_ComputeIsAvailable"; + const string k_ComputeIsAvailableTrue = "1"; + static UIRenderDevice() { @@ -193,13 +197,42 @@ private UIRenderDevice(Shader defaultMaterialShader, uint initialVertexCapacity, SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLES3; } + // TODO: Remove this once case 1148851 has been fixed. + static internal Func getEditorShader = null; + + /// + /// Indicates whether the active subshader of the stock shader has compute capability. Derived shaders are + /// expected to work as the stock shader in that regard. + /// + bool ComputeIsAvailable + { + get + { + if (!s_ComputeIsAvailable.HasValue) + { + // Remove this workaround once case 1148851 has been fixed. In the editor, subshaders aren't stripped + // according to the graphic device capabilities unless the shader is precompiled. Querying tags will + // always return the tags from the first subshader. The editor shader is precompiled and doesn't + // suffer this issue, so we can use it as a reference. + var stockDefaultShader = getEditorShader(); + var stockDefaultMaterial = new Material(stockDefaultShader); + string tagValue = stockDefaultMaterial.GetTag(k_ComputeIsAvailableTag, false); + UIRUtility.Destroy(stockDefaultMaterial); + s_ComputeIsAvailable = tagValue == k_ComputeIsAvailableTrue; + } + + return s_ComputeIsAvailable.Value; + } + } + void CompleteCreation() { if (m_DrawRanges.IsCreated) return; var initialTransformCapacity = m_LazyCreationInitialTransformCapacity; - bool unlimitedTransformCount = SystemInfo.supportsComputeShaders && !OpenGLCoreBelow45(); + + bool unlimitedTransformCount = ComputeIsAvailable; if (!unlimitedTransformCount) // This should be in sync with the fallback value of UIE_SKIN_ELEMS_COUNT_MAX_CONSTANTS in UnityUIE.cginc (minus one for the identity matrix) initialTransformCapacity = 19; @@ -568,18 +601,6 @@ public Material GetStandardMaterial() return m_DefaultMaterial; } - static bool OpenGLCoreBelow45() - { - int maj, min; - if (UIRUtility.GetOpenGLCoreVersion(out maj, out min)) - { - if (maj == 4) - return min < 5; - return maj < 4; - } - else return false; - } - static void SetupStandardMaterial(Material material, DrawingModes mode) { const CompareFunction compFront = CompareFunction.Always; diff --git a/Modules/UIElements/Scheduler.cs b/Modules/UIElements/Scheduler.cs index d81c8ebda5..c38f1095f3 100644 --- a/Modules/UIElements/Scheduler.cs +++ b/Modules/UIElements/Scheduler.cs @@ -111,14 +111,6 @@ internal virtual void OnItemUnscheduled() public virtual bool ShouldUnschedule() { - if (endTimeMs > 0) - { - if (Panel.TimeSinceStartupMs() > endTimeMs) - { - return true; - } - } - if (timerUpdateStopCondition != null) { return timerUpdateStopCondition(); @@ -335,22 +327,32 @@ public void UpdateScheduledEvents() ScheduledItem scheduledItem = m_ScheduledItems[index]; + bool unscheduleItem = false; + if (currentTime - scheduledItem.delayMs >= scheduledItem.startMs) { TimerState timerState = new TimerState { start = scheduledItem.startMs, now = currentTime }; - if (!m_UnscheduleTransactions.Contains(scheduledItem)) // Don't execute items that have been amrker for future removal + if (!m_UnscheduleTransactions.Contains(scheduledItem)) // Don't execute items that have been marked for future removal scheduledItem.PerformTimerUpdate(timerState); scheduledItem.startMs = currentTime; scheduledItem.delayMs = scheduledItem.intervalMs; + + if (scheduledItem.ShouldUnschedule()) + { + unscheduleItem = true; + } } - if (scheduledItem.ShouldUnschedule() && !m_UnscheduleTransactions.Contains(scheduledItem)) - // if the scheduledItem has been unscheduled explicitly in PerformTimerUpdate then it will be in m_UnscheduleTransactions and we shouldn't - // unschedule it again + if (unscheduleItem || (scheduledItem.endTimeMs > 0 && currentTime > scheduledItem.endTimeMs)) { - Unschedule(scheduledItem); + // if the scheduledItem has been unscheduled explicitly in PerformTimerUpdate then + // it will be in m_UnscheduleTransactions and we shouldn't unschedule it again + if (!m_UnscheduleTransactions.Contains(scheduledItem)) + { + Unschedule(scheduledItem); + } } m_LastUpdatedIndex = index; diff --git a/Modules/UIElements/ScrollView.cs b/Modules/UIElements/ScrollView.cs index 2927e0d8a7..9fb9146431 100644 --- a/Modules/UIElements/ScrollView.cs +++ b/Modules/UIElements/ScrollView.cs @@ -147,6 +147,7 @@ void UpdateContentViewTransform() t.y = GUIUtility.RoundToPixelGrid(-offset.y); contentContainer.transform.position = t; + // TODO: Can we get rid of this? this.IncrementVersion(VersionChangeType.Repaint); } diff --git a/Modules/UIElements/Style/InlineStyleAccess.cs b/Modules/UIElements/Style/InlineStyleAccess.cs index 5ca2f3093f..f63391f34d 100644 --- a/Modules/UIElements/Style/InlineStyleAccess.cs +++ b/Modules/UIElements/Style/InlineStyleAccess.cs @@ -175,7 +175,7 @@ StyleEnum IStyle.overflow { if (SetInlineStyle(StylePropertyID.Overflow, value, ve.sharedStyle.overflow)) { - ve.IncrementVersion(VersionChangeType.Styles | VersionChangeType.Layout); + ve.IncrementVersion(VersionChangeType.Styles | VersionChangeType.Layout | VersionChangeType.Overflow); ve.yogaNode.Overflow = (YogaOverflow)ve.computedStyle.overflow.value; } } @@ -344,7 +344,7 @@ StyleLength IStyle.borderTopLeftRadius { if (SetInlineStyle(StylePropertyID.BorderTopLeftRadius, value, ve.sharedStyle.borderTopLeftRadius)) { - ve.IncrementVersion(VersionChangeType.Styles | VersionChangeType.Repaint); + ve.IncrementVersion(VersionChangeType.Styles | VersionChangeType.Repaint | VersionChangeType.BorderRadius); } } } @@ -356,7 +356,7 @@ StyleLength IStyle.borderTopRightRadius { if (SetInlineStyle(StylePropertyID.BorderTopRightRadius, value, ve.sharedStyle.borderTopRightRadius)) { - ve.IncrementVersion(VersionChangeType.Styles | VersionChangeType.Repaint); + ve.IncrementVersion(VersionChangeType.Styles | VersionChangeType.Repaint | VersionChangeType.BorderRadius); } } } @@ -368,7 +368,7 @@ StyleLength IStyle.borderBottomRightRadius { if (SetInlineStyle(StylePropertyID.BorderBottomRightRadius, value, ve.sharedStyle.borderBottomRightRadius)) { - ve.IncrementVersion(VersionChangeType.Styles | VersionChangeType.Repaint); + ve.IncrementVersion(VersionChangeType.Styles | VersionChangeType.Repaint | VersionChangeType.BorderRadius); } } } @@ -380,7 +380,7 @@ StyleLength IStyle.borderBottomLeftRadius { if (SetInlineStyle(StylePropertyID.BorderBottomLeftRadius, value, ve.sharedStyle.borderBottomLeftRadius)) { - ve.IncrementVersion(VersionChangeType.Styles | VersionChangeType.Repaint); + ve.IncrementVersion(VersionChangeType.Styles | VersionChangeType.Repaint | VersionChangeType.BorderRadius); } } } diff --git a/Modules/UIElements/StyleSheets/VisualElementStylesData.cs b/Modules/UIElements/StyleSheets/VisualElementStylesData.cs index 3b7d57f92a..5b42e6676f 100644 --- a/Modules/UIElements/StyleSheets/VisualElementStylesData.cs +++ b/Modules/UIElements/StyleSheets/VisualElementStylesData.cs @@ -244,26 +244,27 @@ internal void ApplyRule(StyleSheet sheet, int specificity, StyleRule rule, Style if (handles[0].valueType == StyleValueType.Keyword && handles[0].valueIndex == (int)StyleValueKeyword.Initial) { ApplyInitialStyleValue(propertyID, specificity); - return; } - - switch (propertyID) + else { - case StylePropertyID.Unknown: - break; - case StylePropertyID.Custom: - ApplyCustomStyleProperty(sheet, styleProperty, specificity); - break; - case StylePropertyID.BorderRadius: - case StylePropertyID.BorderWidth: - case StylePropertyID.Flex: - case StylePropertyID.Margin: - case StylePropertyID.Padding: - ApplyShorthandProperty(sheet, propertyID, styleProperty.values, specificity); - break; - default: - ApplyStyleProperty(s_StyleSheetApplicator, sheet, propertyID, handles, specificity); - break; + switch (propertyID) + { + case StylePropertyID.Unknown: + break; + case StylePropertyID.Custom: + ApplyCustomStyleProperty(sheet, styleProperty, specificity); + break; + case StylePropertyID.BorderRadius: + case StylePropertyID.BorderWidth: + case StylePropertyID.Flex: + case StylePropertyID.Margin: + case StylePropertyID.Padding: + ApplyShorthandProperty(sheet, propertyID, styleProperty.values, specificity); + break; + default: + ApplyStyleProperty(s_StyleSheetApplicator, sheet, propertyID, handles, specificity); + break; + } } } } diff --git a/Modules/UIElements/VisualElement.cs b/Modules/UIElements/VisualElement.cs index 3f846d394d..30a32c017c 100644 --- a/Modules/UIElements/VisualElement.cs +++ b/Modules/UIElements/VisualElement.cs @@ -263,10 +263,7 @@ Vector3 ITransform.scale if (m_Scale == value) return; m_Scale = value; - IncrementVersion(VersionChangeType.Transform); - - // This will change how we measure text - IncrementVersion(VersionChangeType.Layout); + IncrementVersion(VersionChangeType.Transform | VersionChangeType.Layout /*This will change how we measure text*/); } } @@ -320,6 +317,13 @@ internal set if (isLayoutManual && m_Layout == value) return; + Rect lastLayout = layout; + VersionChangeType changeType = 0; + if (!Mathf.Approximately(lastLayout.x, value.x) || !Mathf.Approximately(lastLayout.y, value.y)) + changeType |= VersionChangeType.Transform; + if (!Mathf.Approximately(lastLayout.width, value.width) || !Mathf.Approximately(lastLayout.height, value.height)) + changeType |= VersionChangeType.Size; + // set results so we can read straight back in get without waiting for a pass m_Layout = value; isLayoutManual = true; @@ -338,7 +342,8 @@ internal set styleAccess.width = value.width; styleAccess.height = value.height; - IncrementVersion(VersionChangeType.Transform); + if (changeType != 0) + IncrementVersion(changeType); } } @@ -557,13 +562,17 @@ private void UpdateWorldClip() float x2 = Mathf.Min(wb.xMax, m_WorldClip.xMax); float y1 = Mathf.Max(wb.yMin, m_WorldClip.yMin); float y2 = Mathf.Min(wb.yMax, m_WorldClip.yMax); - m_WorldClip = new Rect(x1, y1, x2 - x1, y2 - y1); + float width = Mathf.Max(x2 - x1, 0); + float height = Mathf.Max(y2 - y1, 0); + m_WorldClip = new Rect(x1, y1, width, height); x1 = Mathf.Max(wb.xMin, m_WorldClipMinusGroup.xMin); x2 = Mathf.Min(wb.xMax, m_WorldClipMinusGroup.xMax); y1 = Mathf.Max(wb.yMin, m_WorldClipMinusGroup.yMin); y2 = Mathf.Min(wb.yMax, m_WorldClipMinusGroup.yMax); - m_WorldClipMinusGroup = new Rect(x1, y1, x2 - x1, y2 - y1); + width = Mathf.Max(x2 - x1, 0); + height = Mathf.Max(y2 - y1, 0); + m_WorldClipMinusGroup = new Rect(x1, y1, width, height); } } else @@ -1189,6 +1198,12 @@ internal void SetSharedStyles(VisualElementStylesData sharedStyle) return; } + var previousOverflow = m_Style.overflow; + var previousBorderBottomLeftRadius = m_Style.borderBottomLeftRadius; + var previousBorderBottomRightRadius = m_Style.borderBottomRightRadius; + var previousBorderTopLeftRadius = m_Style.borderTopLeftRadius; + var previousBorderTopRightRadius = m_Style.borderTopRightRadius; + if (hasInlineStyle) { m_Style.Apply(sharedStyle, StylePropertyApplyMode.CopyIfNotInline); @@ -1202,9 +1217,22 @@ internal void SetSharedStyles(VisualElementStylesData sharedStyle) FinalizeLayout(); + VersionChangeType changes = VersionChangeType.Styles | VersionChangeType.Layout | VersionChangeType.Repaint; + + if (m_Style.overflow != previousOverflow) + changes |= VersionChangeType.Overflow; + + if (previousBorderBottomLeftRadius != m_Style.borderBottomLeftRadius || + previousBorderBottomRightRadius != m_Style.borderBottomRightRadius || + previousBorderTopLeftRadius != m_Style.borderTopLeftRadius || + previousBorderTopRightRadius != m_Style.borderTopRightRadius) + { + changes |= VersionChangeType.BorderRadius; + } + // This is a pre-emptive since we do not know if style changes actually cause a repaint or a layout // But those should be the only possible type of changes needed - IncrementVersion(VersionChangeType.Styles | VersionChangeType.Layout | VersionChangeType.Repaint); + IncrementVersion(changes); } internal void ResetPositionProperties() diff --git a/Modules/UIElements/VisualTreeLayoutUpdater.cs b/Modules/UIElements/VisualTreeLayoutUpdater.cs index 6e3ca07e5a..102360a39a 100644 --- a/Modules/UIElements/VisualTreeLayoutUpdater.cs +++ b/Modules/UIElements/VisualTreeLayoutUpdater.cs @@ -67,7 +67,7 @@ private void UpdateSubTree(VisualElement root) { root.IncrementVersion(VersionChangeType.Transform); } - root.IncrementVersion(VersionChangeType.Clip); + root.IncrementVersion(VersionChangeType.Size); root.renderData.lastLayout = yogaRect; } diff --git a/Modules/UIElements/VisualTreeTransformClipUpdater.cs b/Modules/UIElements/VisualTreeTransformClipUpdater.cs index 61346bb308..934135c623 100644 --- a/Modules/UIElements/VisualTreeTransformClipUpdater.cs +++ b/Modules/UIElements/VisualTreeTransformClipUpdater.cs @@ -3,6 +3,7 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; +using System.Diagnostics; namespace UnityEngine.UIElements { @@ -18,51 +19,45 @@ public override string description public override void OnVersionChanged(VisualElement ve, VersionChangeType versionChangeType) { - if ((versionChangeType & (VersionChangeType.Transform | VersionChangeType.Clip)) == 0) + if ((versionChangeType & (VersionChangeType.Transform | VersionChangeType.Size | VersionChangeType.Overflow)) == 0) return; - if ((versionChangeType & VersionChangeType.Transform) == VersionChangeType.Transform && (!ve.isWorldTransformDirty || !ve.isWorldClipDirty)) - DirtyTransformClipHierarchy(ve); // Dirty both transform and clip when the transform changes - else if ((versionChangeType & VersionChangeType.Clip) == VersionChangeType.Clip && !ve.isWorldClipDirty) - DirtyClipHierarchy(ve); + // According to the flags, what operations must be done? + bool mustDirtyWorldTransform = (versionChangeType & VersionChangeType.Transform) != 0; + bool mustDirtyWorldClip = (versionChangeType & (VersionChangeType.Transform | VersionChangeType.Size | VersionChangeType.Overflow)) != 0; + + // Are these operations already done? + mustDirtyWorldTransform = mustDirtyWorldTransform && !ve.isWorldTransformDirty; + mustDirtyWorldClip = mustDirtyWorldClip && !ve.isWorldClipDirty; + + if (mustDirtyWorldTransform || mustDirtyWorldClip) + DirtyHierarchy(ve, mustDirtyWorldTransform, mustDirtyWorldClip); DirtyBoundingBoxHierarchy(ve); ++m_Version; } - private void DirtyTransformClipHierarchy(VisualElement ve) + static void DirtyHierarchy(VisualElement ve, bool mustDirtyWorldTransform, bool mustDirtyWorldClip) { - ve.isWorldTransformDirty = true; - ve.isWorldClipDirty = true; + if (mustDirtyWorldTransform) + ve.isWorldTransformDirty = true; - int count = ve.hierarchy.childCount; - for (int i = 0; i < count; i++) - { - var child = ve.hierarchy[i]; - if (child.isWorldTransformDirty && child.isWorldClipDirty) - continue; - - DirtyTransformClipHierarchy(child); - } - } - - private void DirtyClipHierarchy(VisualElement ve) - { - ve.isWorldClipDirty = true; + if (mustDirtyWorldClip) + ve.isWorldClipDirty = true; int count = ve.hierarchy.childCount; for (int i = 0; i < count; i++) { var child = ve.hierarchy[i]; - if (child.isWorldClipDirty) - continue; - DirtyClipHierarchy(child); + if (mustDirtyWorldTransform && !child.isWorldTransformDirty || + mustDirtyWorldClip && !child.isWorldClipDirty) + DirtyHierarchy(child, mustDirtyWorldTransform, mustDirtyWorldClip); } } - private void DirtyBoundingBoxHierarchy(VisualElement ve) + static void DirtyBoundingBoxHierarchy(VisualElement ve) { ve.isBoundingBoxDirty = true; var parent = ve.hierarchy.parent; diff --git a/Modules/UIElementsDebuggerEditor/DebuggerTreeView.cs b/Modules/UIElementsDebuggerEditor/DebuggerTreeView.cs index f665f8e093..0e3448e72f 100644 --- a/Modules/UIElementsDebuggerEditor/DebuggerTreeView.cs +++ b/Modules/UIElementsDebuggerEditor/DebuggerTreeView.cs @@ -31,7 +31,7 @@ public IEnumerable treeItems } } - private IList m_TreeRootItems; + private IList m_TreeRootItems = new List(); private TreeView m_TreeView; private HighlightOverlayPainter m_TreeViewHoverOverlay; @@ -148,10 +148,20 @@ public void RebuildTree(IPanelDebug panelDebug) m_Container.Clear(); int nextId = 1; - m_TreeRootItems = GetTreeItemsFromVisualTree(panelDebug?.visualTree, ref nextId); - if (panelDebug?.visualTree != null) - m_TreeRootItems.Insert(0, new TreeViewItem(0, panelDebug.visualTree)); + m_TreeRootItems.Clear(); + + var visualTree = panelDebug?.visualTree; + if (visualTree != null) + { + var rootItem = new TreeViewItem(nextId++, visualTree); + m_TreeRootItems.Add(rootItem); + + var childItems = new List(); + AddTreeItemsForElement(childItems, visualTree, ref nextId); + + rootItem.AddChildren(childItems); + } Func makeItem = () => { @@ -278,36 +288,30 @@ public void SelectElement(VisualElement element, string query, SearchHighlight s } } - private IList GetTreeItemsFromVisualTree(VisualElement parent, ref int nextId) + private void AddTreeItemsForElement(IList items, VisualElement ve, ref int nextId) { - List items = null; - - if (parent == null) - return null; + if (ve == null) + return; - int count = parent.hierarchy.childCount; + int count = ve.hierarchy.childCount; if (count == 0) - return null; + return; for (int i = 0; i < count; i++) { - if (items == null) - items = new List(); - - var element = parent.hierarchy[i]; + var child = ve.hierarchy[i]; - var item = new TreeViewItem(nextId, element); - items.Add(item); + var treeItem = new TreeViewItem(nextId, child); + items.Add(treeItem); nextId++; - var childItems = GetTreeItemsFromVisualTree(element, ref nextId); - if (childItems == null) + var childItems = new List(); + AddTreeItemsForElement(childItems, child, ref nextId); + if (childItems.Count == 0) continue; - item.AddChildren(childItems); + treeItem.AddChildren(childItems); } - - return items; } } } diff --git a/Modules/UIElementsDebuggerEditor/PanelDebugger.cs b/Modules/UIElementsDebuggerEditor/PanelDebugger.cs index 248689612a..9bf8134e0f 100644 --- a/Modules/UIElementsDebuggerEditor/PanelDebugger.cs +++ b/Modules/UIElementsDebuggerEditor/PanelDebugger.cs @@ -23,6 +23,7 @@ public override string ToString() } } + [SerializeField] private string m_LastVisualTreeName; @@ -35,6 +36,17 @@ public override string ToString() private IVisualElementScheduledItem m_ConnectWindowScheduledItem; private IVisualElementScheduledItem m_RestoreSelectionScheduledItem; + private Dictionary m_PanelToEditorWindow; + + protected void TryFocusCorrespondingWindow(Panel panel) + { + EditorWindow window; + if (m_PanelToEditorWindow.TryGetValue(panel, out window)) + { + window.Focus(); + } + } + public IPanelDebug panelDebug { get; set; } protected IPanel panel @@ -61,6 +73,7 @@ public void OnEnable() RefreshPanelChoices(); }, TrickleDown.TrickleDown); + m_PanelToEditorWindow = new Dictionary(); m_PanelChoices = new List(); m_PanelSelect = new ToolbarMenu() { name = "panelSelectPopup", variant = ToolbarMenu.Variant.Popup}; m_PanelSelect.text = "Select a panel"; @@ -128,7 +141,7 @@ protected virtual void OnRestorePanelSelection() {} private void RefreshPanelChoices() { m_PanelChoices.Clear(); - + m_PanelToEditorWindow.Clear(); List guiViews = new List(); GUIViewDebuggerHelper.GetViews(guiViews); var it = UIElementsUtility.GetPanelsIterator(); @@ -145,6 +158,8 @@ private void RefreshPanelChoices() var p = it.Current.Value; m_PanelChoices.Add(new PanelChoice { panel = p, name = p.name }); + if (hostView != null && hostView.actualView != null) + m_PanelToEditorWindow.Add(p, hostView.actualView); } var menu = m_PanelSelect.menu; diff --git a/Modules/UIElementsDebuggerEditor/StylesDebugger.cs b/Modules/UIElementsDebuggerEditor/StylesDebugger.cs index 153780ca34..74822b18d9 100644 --- a/Modules/UIElementsDebuggerEditor/StylesDebugger.cs +++ b/Modules/UIElementsDebuggerEditor/StylesDebugger.cs @@ -203,7 +203,6 @@ private void DrawProperties() GUILayout.EndHorizontal(); var customProperties = m_SelectedElement.specifiedStyle.m_CustomProperties; - bool anyChanged = false; if (customProperties != null && customProperties.Any()) { @@ -345,7 +344,6 @@ private void DrawProperties() if (EditorGUI.EndChangeCheck()) { - anyChanged = true; string propertyName = field.Name; var inlineStyle = typeof(IStyle).GetProperty(propertyName); inlineStyle.SetValue(m_SelectedElement.style, val, null); @@ -373,12 +371,6 @@ private void DrawProperties() EditorGUILayout.EndHorizontal(); } - - if (anyChanged) - { - m_PanelDebug.visualTree.IncrementVersion(VersionChangeType.Styles | VersionChangeType.StyleSheet | - VersionChangeType.Layout | VersionChangeType.Transform | VersionChangeType.Repaint); - } } private void InitClassList() @@ -556,19 +548,28 @@ public MatchedRule(SelectorMatchRecord matchRecord) } } + public override int GetHashCode() + { + unchecked + { + var hashCode = matchRecord.GetHashCode(); + hashCode = (hashCode * 397) ^ (displayPath != null ? displayPath.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ lineNumber; + hashCode = (hashCode * 397) ^ (fullPath != null ? fullPath.GetHashCode() : 0); + return hashCode; + } + } + private sealed class LineNumberFullPathEqualityComparer : IEqualityComparer { public bool Equals(MatchedRule x, MatchedRule y) { - return x.lineNumber == y.lineNumber && string.Equals(x.fullPath, y.fullPath); + return x.lineNumber == y.lineNumber && string.Equals(x.fullPath, y.fullPath) && string.Equals(x.displayPath, y.displayPath); } public int GetHashCode(MatchedRule obj) { - unchecked - { - return (obj.lineNumber * 397) ^ (obj.fullPath != null ? obj.fullPath.GetHashCode() : 0); - } + return obj.GetHashCode(); } } diff --git a/Modules/UIElementsDebuggerEditor/UIElementsDebugger.cs b/Modules/UIElementsDebuggerEditor/UIElementsDebugger.cs index d0044e3550..fe912bd261 100644 --- a/Modules/UIElementsDebuggerEditor/UIElementsDebugger.cs +++ b/Modules/UIElementsDebuggerEditor/UIElementsDebugger.cs @@ -3,6 +3,7 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; +using UnityEditor.ShortcutManagement; using UnityEngine; using UnityEngine.UIElements; @@ -53,6 +54,8 @@ internal class UIElementsDebugger : PanelDebugger, IGlobalPanelDebugger const string k_DefaultStyleSheetPath = "StyleSheets/UIElementsDebugger/UIElementsDebugger.uss"; const string k_DefaultDarkStyleSheetPath = "StyleSheets/UIElementsDebugger/UIElementsDebuggerDark.uss"; const string k_DefaultLightStyleSheetPath = "StyleSheets/UIElementsDebugger/UIElementsDebuggerLight.uss"; + public const string k_WindowPath = "Window/Analysis/UIElements Debugger"; + public static readonly string WindowName = L10n.Tr("UIElements Debugger"); private ToolbarToggle m_PickToggle; private ToolbarToggle m_ShowLayoutToggle; @@ -74,13 +77,19 @@ internal class UIElementsDebugger : PanelDebugger, IGlobalPanelDebugger private bool m_ShowLayoutBound = false; private bool m_ShowRepaintOverlay = false; - [MenuItem("Window/Analysis/UIElements Debugger", false, 101, false)] - public static void Open() + [MenuItem(k_WindowPath, false, 101, false)] + private static void Open() { var window = CreateDebuggerWindow(); window.Show(); } + [Shortcut(k_WindowPath, KeyCode.F5, ShortcutModifiers.Action)] + private static void DebugWindowShortcut() + { + OpenAndInspectWindow(EditorWindow.focusedWindow); + } + public static void OpenAndInspectWindow(EditorWindow window) { var debuggerWindow = CreateDebuggerWindow(); @@ -91,7 +100,7 @@ public static void OpenAndInspectWindow(EditorWindow window) private static UIElementsDebugger CreateDebuggerWindow() { var window = CreateInstance(); - window.titleContent = new GUIContent("UIElements Debugger"); + window.titleContent = EditorGUIUtility.TextContent(WindowName); return window; } @@ -121,7 +130,20 @@ private static UIElementsDebugger CreateDebuggerWindow() m_PickToggle = new ToolbarToggle() { name = "pickToggle" }; m_PickToggle.text = "Pick Element"; - m_PickToggle.RegisterValueChangedCallback((e) => m_PickElement = e.newValue); + m_PickToggle.RegisterValueChangedCallback((e) => + { + m_PickElement = e.newValue; + // On OSX, as focus-follow-mouse is not supported, + // we explicitly focus the EditorWindow when enabling picking + if (Application.platform == RuntimePlatform.OSXEditor) + { + Panel p = m_DebuggerSelection.panel as Panel; + if (p != null) + { + TryFocusCorrespondingWindow(p); + } + } + }); m_Toolbar.Add(m_PickToggle); diff --git a/Modules/UIElementsSamplesEditor/Snippets/ListViewSnippet.cs b/Modules/UIElementsSamplesEditor/Snippets/ListViewSnippet.cs new file mode 100644 index 0000000000..e78fe7f55f --- /dev/null +++ b/Modules/UIElementsSamplesEditor/Snippets/ListViewSnippet.cs @@ -0,0 +1,48 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using UnityEditor.UIElements; +using UnityEngine; +using UnityEngine.UIElements; +using System.Collections.Generic; +using System; + +namespace UnityEditor.UIElements.Samples +{ + internal class ListViewSnippet : ElementSnippet + { + internal override void Apply(VisualElement container) + { + /// + // Create some list of data, here simply numbers in interval [1, 1000] + const int itemCount = 1000; + var items = new List(itemCount); + for (int i = 1; i <= itemCount; i++) + items.Add(i.ToString()); + + // The "makeItem" function will be called as needed + // when the ListView needs more items to render + Func makeItem = () => new Label(); + + // As the user scrolls through the list, the ListView object + // will recycle elements created by the "makeItem" + // and invoke the "bindItem" callback to associate + // the element with the matching data item (specified as an index in the list) + Action bindItem = (e, i) => (e as Label).text = items[i]; + + var listView = container.Q(); + listView.makeItem = makeItem; + listView.bindItem = bindItem; + listView.itemsSource = items; + listView.selectionType = SelectionType.Multiple; + + // Callback invoked when the user double clicks an item + listView.onItemChosen += obj => Debug.Log(obj); + + // Callback invoked when the user changes the selection inside the ListView + listView.onSelectionChanged += objects => Debug.Log(objects); + /// + } + } +} diff --git a/Modules/UIElementsSamplesEditor/UIElementsSamples.cs b/Modules/UIElementsSamplesEditor/UIElementsSamples.cs index 1fd7c22236..7b83582764 100644 --- a/Modules/UIElementsSamplesEditor/UIElementsSamples.cs +++ b/Modules/UIElementsSamplesEditor/UIElementsSamples.cs @@ -86,6 +86,7 @@ public void OnEnable() new SampleTreeItem("Label", LabelSnippet.Create), new SampleTreeItem("Text Field", TextFieldSnippet.Create), new SampleTreeItem("Object Field", ObjectFieldSnippet.Create), + new SampleTreeItem("List View", ListViewSnippet.Create), new SampleTreeItem("Numeric Fields", MakeNumericFieldsPanel, new List>() { new SampleTreeItem("Integer", IntegerFieldSnippet.Create), diff --git a/Modules/UnityWebRequest/Public/UploadHandler/UploadHandler.bindings.cs b/Modules/UnityWebRequest/Public/UploadHandler/UploadHandler.bindings.cs index 190ab10188..aaaebe3255 100644 --- a/Modules/UnityWebRequest/Public/UploadHandler/UploadHandler.bindings.cs +++ b/Modules/UnityWebRequest/Public/UploadHandler/UploadHandler.bindings.cs @@ -66,9 +66,18 @@ public float progress } internal virtual byte[] GetData() { return null; } - internal virtual string GetContentType() { return "text/plain"; } - internal virtual void SetContentType(string newContentType) {} - internal virtual float GetProgress() { return 0.5f; } + internal virtual string GetContentType() { return InternalGetContentType(); } + internal virtual void SetContentType(string newContentType) { InternalSetContentType(newContentType); } + internal virtual float GetProgress() { return InternalGetProgress(); } + + [NativeMethod("GetContentType")] + private extern string InternalGetContentType(); + + [NativeMethod("SetContentType")] + private extern void InternalSetContentType(string newContentType); + + [NativeMethod("GetProgress")] + private extern float InternalGetProgress(); } [StructLayout(LayoutKind.Sequential)] @@ -84,34 +93,13 @@ public UploadHandlerRaw(byte[] data) m_Ptr = Create(this, data); } - [NativeMethod("GetContentType")] - private extern string InternalGetContentType(); - - [NativeMethod("SetContentType")] - private extern void InternalSetContentType(string newContentType); - private extern byte[] InternalGetData(); - [NativeMethod("GetProgress")] - private extern float InternalGetProgress(); - - internal override string GetContentType() { return InternalGetContentType(); } - - internal override void SetContentType(string newContentType) - { - InternalSetContentType(newContentType); - } - internal override byte[] GetData() { return InternalGetData(); } - internal override float GetProgress() - { - return InternalGetProgress(); - } - } [StructLayout(LayoutKind.Sequential)] diff --git a/Modules/UnityWebRequest/Public/WebRequestExtensions.cs b/Modules/UnityWebRequest/Public/WebRequestExtensions.cs index 5f368fbe41..a99cea62ba 100644 --- a/Modules/UnityWebRequest/Public/WebRequestExtensions.cs +++ b/Modules/UnityWebRequest/Public/WebRequestExtensions.cs @@ -304,7 +304,7 @@ public static string EscapeURL(string s, Encoding e) if (e == null) return null; - var bytes = Encoding.UTF8.GetBytes(s); + var bytes = e.GetBytes(s); var decodedBytes = WWWTranscoder.URLEncode(bytes); return e.GetString(decodedBytes); } @@ -322,7 +322,7 @@ public static string UnEscapeURL(string s, Encoding e) if (s.IndexOf('%') == -1 && s.IndexOf('+') == -1) return s; - var bytes = Encoding.UTF8.GetBytes(s); + var bytes = e.GetBytes(s); var decodedBytes = WWWTranscoder.URLDecode(bytes); return e.GetString(decodedBytes); } diff --git a/Modules/VR/HoloLens/HolographicEmulation/HolographicRemoting.cs b/Modules/VR/HoloLens/HolographicEmulation/HolographicRemoting.cs index 9ccf120add..691f97c863 100644 --- a/Modules/VR/HoloLens/HolographicEmulation/HolographicRemoting.cs +++ b/Modules/VR/HoloLens/HolographicEmulation/HolographicRemoting.cs @@ -17,8 +17,12 @@ public static HolographicStreamerConnectionState ConnectionState return HolographicStreamerConnectionState.Disconnected; } } - public static void Connect(string clientName, int maxBitRate = 9999) + { + Connect(clientName, maxBitRate, RemoteDeviceVersion.V1); + } + + public static void Connect(string clientName, int maxBitRate, RemoteDeviceVersion deviceVersion) { } diff --git a/Modules/VR/HoloLens/ScriptBindings/HolographicEmulation.bindings.cs b/Modules/VR/HoloLens/ScriptBindings/HolographicEmulation.bindings.cs index 717b731d1b..9a5093c302 100644 --- a/Modules/VR/HoloLens/ScriptBindings/HolographicEmulation.bindings.cs +++ b/Modules/VR/HoloLens/ScriptBindings/HolographicEmulation.bindings.cs @@ -33,6 +33,13 @@ internal enum EmulationMode Simulated }; + [NativeHeader("Modules/VR/HoloLens/PerceptionRemoting.h")] + public enum RemoteDeviceVersion + { + V1, + V2 + } + [NativeHeader("Modules/VR/HoloLens/HolographicEmulation/HolographicEmulationManager.h")] [StaticAccessor("HolographicEmulation::HolographicEmulationManager::Get()", StaticAccessorType.Dot)] internal partial class HolographicEmulationHelper @@ -46,6 +53,8 @@ internal partial class HolographicEmulationHelper [NativeConditional("ENABLE_HOLOLENS_MODULE")] internal partial class PerceptionRemoting { + internal static extern void SetRemoteDeviceVersion(RemoteDeviceVersion remoteDeviceVersion); + internal static extern void Connect(string clientName); internal static extern void Disconnect(); diff --git a/Modules/VR/HoloLens/ScriptBindings/SpatialMapping.bindings.cs b/Modules/VR/HoloLens/ScriptBindings/SpatialMapping.bindings.cs index 3fc6f8084e..8a18caf28d 100644 --- a/Modules/VR/HoloLens/ScriptBindings/SpatialMapping.bindings.cs +++ b/Modules/VR/HoloLens/ScriptBindings/SpatialMapping.bindings.cs @@ -60,13 +60,14 @@ public SurfaceData(SurfaceId _id, MeshFilter _outputMesh, WorldAnchor _outputAnc // [MovedFrom("UnityEngine.VR.WSA")] [UsedByNativeCode] - [StaticAccessor("SurfaceObserver", StaticAccessorType.DoubleColon)] + [StaticAccessor("Unity::SurfaceObserver", StaticAccessorType.DoubleColon)] [NativeHeader("Modules/VR/HoloLens/SpatialMapping/SurfaceObserver.h")] [NativeHeader("VRScriptingClasses.h")] [StructLayout(LayoutKind.Sequential)] // needed for IntPtr binding classes sealed public class SurfaceObserver : IDisposable { - internal IntPtr m_Observer; // Native object + const int k_InvalidObserverId = 0; + internal int m_Observer; // Native object id public delegate void SurfaceChangedDelegate(SurfaceId surfaceId, SurfaceChange changeType, Bounds bounds, DateTime updateTime); public delegate void SurfaceDataReadyDelegate(SurfaceData bakedData, bool outputWritten, float elapsedBakeTimeSeconds); @@ -105,43 +106,69 @@ public SurfaceObserver() [NativeConditional("ENABLE_HOLOLENS_MODULE")] [NativeName("Create")] - private static extern IntPtr Internal_Create(System.Object surfaceObserver); + private static extern int Internal_Create(System.Object surfaceObserver); ~SurfaceObserver() { - if (m_Observer != IntPtr.Zero) + if (m_Observer != k_InvalidObserverId) { DestroyThreaded(); - m_Observer = IntPtr.Zero; + m_Observer = k_InvalidObserverId; GC.SuppressFinalize(this); } } - [ThreadAndSerializationSafe] - [NativeConditional("ENABLE_HOLOLENS_MODULE")] - private extern void DestroyThreaded(); - public void Dispose() { - if (m_Observer != IntPtr.Zero) + if (m_Observer != k_InvalidObserverId) { Destroy(); - m_Observer = IntPtr.Zero; + m_Observer = k_InvalidObserverId; } GC.SuppressFinalize(this); } + private void Destroy() + { + Internal_Destroy(m_Observer); + } + [NativeConditional("ENABLE_HOLOLENS_MODULE")] - private extern void Destroy(); + private static extern void Internal_Destroy(int id); + public void SetVolumeAsAxisAlignedBox(Vector3 origin, Vector3 extents) + { + if (m_Observer != k_InvalidObserverId) Internal_SetVolumeAsAxisAlignedBox(m_Observer, origin, extents); + } + + private void DestroyThreaded() + { + Internal_DestroyThreaded(m_Observer); + } + + [ThreadAndSerializationSafe] [NativeConditional("ENABLE_HOLOLENS_MODULE")] - public extern void SetVolumeAsAxisAlignedBox(Vector3 origin, Vector3 extents); + private static extern void Internal_DestroyThreaded(int id); + + + [NativeConditional("ENABLE_HOLOLENS_MODULE")] + private static extern void Internal_SetVolumeAsAxisAlignedBox(int id, Vector3 origin, Vector3 extents); + + public void SetVolumeAsSphere(Vector3 origin, float radiusMeters) + { + if (m_Observer != k_InvalidObserverId) Internal_SetVolumeAsSphere(m_Observer, origin, radiusMeters); + } [NativeConditional("ENABLE_HOLOLENS_MODULE")] - public extern void SetVolumeAsSphere(Vector3 origin, float radiusMeters); + private static extern void Internal_SetVolumeAsSphere(int id, Vector3 origin, float radiusMeters); + + public void SetVolumeAsOrientedBox(Vector3 origin, Vector3 extents, Quaternion orientation) + { + if (m_Observer != k_InvalidObserverId) Internal_SetVolumeAsOrientedBox(m_Observer, origin, extents, orientation); + } [NativeConditional("ENABLE_HOLOLENS_MODULE")] - public extern void SetVolumeAsOrientedBox(Vector3 origin, Vector3 extents, Quaternion orientation); + private static extern void Internal_SetVolumeAsOrientedBox(int id, Vector3 origin, Vector3 extents, Quaternion orientation); public void SetVolumeAsFrustum(Plane[] planes) { @@ -151,15 +178,19 @@ public void SetVolumeAsFrustum(Plane[] planes) if (planes.Length != 6) throw new ArgumentException("Planes array must be 6 items long", "planes"); - SetVolumeAsFrustum_Internal(planes); + if (m_Observer != k_InvalidObserverId) Internal_SetVolumeAsFrustum(m_Observer, planes); } [NativeConditional("ENABLE_HOLOLENS_MODULE")] - [NativeName("SetVolumeAsFrustum")] - private extern void SetVolumeAsFrustum_Internal([NotNull] Plane[] planes); + private static extern void Internal_SetVolumeAsFrustum(int id, [NotNull] Plane[] planes); + + public void Update(SurfaceChangedDelegate onSurfaceChanged) + { + if (m_Observer != k_InvalidObserverId) Internal_Update(m_Observer, onSurfaceChanged); + } [NativeConditional("ENABLE_HOLOLENS_MODULE")] - public extern void Update([NotNull] SurfaceChangedDelegate onSurfaceChanged); + private static extern void Internal_Update(int id, [NotNull] SurfaceChangedDelegate onSurfaceChanged); public bool RequestMeshAsync(SurfaceData dataRequest, SurfaceDataReadyDelegate onDataReady) { @@ -202,7 +233,7 @@ public bool RequestMeshAsync(SurfaceData dataRequest, SurfaceDataReadyDelegate o [NativeConditional("ENABLE_HOLOLENS_MODULE")] [NativeName("AddToWorkQueue")] - private static extern bool Internal_AddToWorkQueue(IntPtr observer, SurfaceDataReadyDelegate onDataReady, int surfaceId, MeshFilter filter, WorldAnchor wa, MeshCollider mc, float trisPerCubicMeter, bool createColliderData); + private static extern bool Internal_AddToWorkQueue(int observer, SurfaceDataReadyDelegate onDataReady, int surfaceId, MeshFilter filter, WorldAnchor wa, MeshCollider mc, float trisPerCubicMeter, bool createColliderData); } } diff --git a/Modules/VR/ScriptBindings/XR.bindings.cs b/Modules/VR/ScriptBindings/XR.bindings.cs index 8214d8c6cf..c40787c2e6 100644 --- a/Modules/VR/ScriptBindings/XR.bindings.cs +++ b/Modules/VR/ScriptBindings/XR.bindings.cs @@ -39,7 +39,6 @@ extern public static bool enabled [StaticAccessor("GetIVRDevice()", StaticAccessorType.ArrowWithDefaultReturnIfNull)] get; - [NativeMethod("VRModuleBindings::SetDeviceEnabled", true)] set; } diff --git a/Modules/VREditor/Mono/Oculus/VRCustomOptionsOculus.cs b/Modules/VREditor/Mono/Oculus/VRCustomOptionsOculus.cs index 3ca57aae9d..e2e4609dc8 100644 --- a/Modules/VREditor/Mono/Oculus/VRCustomOptionsOculus.cs +++ b/Modules/VREditor/Mono/Oculus/VRCustomOptionsOculus.cs @@ -14,10 +14,14 @@ internal class VRCustomOptionsOculus : VRCustomOptions static GUIContent s_SharedDepthBufferLabel = EditorGUIUtility.TextContent("Shared Depth Buffer|Enable depth buffer submission to allow for overlay depth occlusion, etc."); static GUIContent s_DashSupportLabel = EditorGUIUtility.TextContent("Dash Support|If enabled, pressing the home button brings up Dash, otherwise it brings up the older universal menu."); static GUIContent s_LowOverheadModeLabel = EditorGUIUtility.TextContent("Low Overhead Mode|If enabled, the GLES graphics driver will bypass validation code, potentially running faster."); + static GUIContent s_ProtectedContextLabel = EditorGUIUtility.TextContent("Protected Context|If enabled, the Oculus SDK will create a protected graphics context. Has a slight overhead; only use if necessary."); + static GUIContent s_V2SigningLabel = EditorGUIUtility.TextContent("V2 Signing (Quest)|Enable APK v2 signing if building for Oculus Quest. Disable v2 signing if building for Gear VR or Oculus Go."); SerializedProperty m_SharedDepthBuffer; SerializedProperty m_DashSupport; SerializedProperty m_LowOverheadMode; + SerializedProperty m_ProtectedContext; + SerializedProperty m_V2Signing; public override void Initialize(SerializedObject settings) { @@ -30,6 +34,8 @@ public override void Initialize(SerializedObject settings, string propertyName) m_SharedDepthBuffer = FindPropertyAssert("sharedDepthBuffer"); m_DashSupport = FindPropertyAssert("dashSupport"); m_LowOverheadMode = FindPropertyAssert("lowOverheadMode"); + m_ProtectedContext = FindPropertyAssert("protectedContext"); + m_V2Signing = FindPropertyAssert("v2Signing"); } public override Rect Draw(BuildTargetGroup target, Rect rect) @@ -70,6 +76,28 @@ public override Rect Draw(BuildTargetGroup target, Rect rect) m_LowOverheadMode.boolValue = boolValue; } EditorGUI.EndProperty(); + rect.y += rect.height + EditorGUIUtility.standardVerticalSpacing; + + rect.height = EditorGUIUtility.singleLineHeight; + label = EditorGUI.BeginProperty(rect, s_ProtectedContextLabel, m_ProtectedContext); + EditorGUI.BeginChangeCheck(); + boolValue = EditorGUI.Toggle(rect, label, m_ProtectedContext.boolValue); + if (EditorGUI.EndChangeCheck()) + { + m_ProtectedContext.boolValue = boolValue; + } + EditorGUI.EndProperty(); + rect.y += rect.height + EditorGUIUtility.standardVerticalSpacing; + + rect.height = EditorGUIUtility.singleLineHeight; + label = EditorGUI.BeginProperty(rect, s_V2SigningLabel, m_V2Signing); + EditorGUI.BeginChangeCheck(); + boolValue = EditorGUI.Toggle(rect, label, m_V2Signing.boolValue); + if (EditorGUI.EndChangeCheck()) + { + m_V2Signing.boolValue = boolValue; + } + EditorGUI.EndProperty(); } rect.y += rect.height + EditorGUIUtility.standardVerticalSpacing; @@ -85,7 +113,7 @@ public override float GetHeight(BuildTargetGroup target) } else { - return (EditorGUIUtility.singleLineHeight * 1.0f) + (EditorGUIUtility.standardVerticalSpacing * 2.0f); + return (EditorGUIUtility.singleLineHeight * 3.0f) + (EditorGUIUtility.standardVerticalSpacing * 4.0f); } } } diff --git a/Modules/VREditor/Mono/PlayerSettingsEditorVR.cs b/Modules/VREditor/Mono/PlayerSettingsEditorVR.cs index 42742768d1..5de832a668 100644 --- a/Modules/VREditor/Mono/PlayerSettingsEditorVR.cs +++ b/Modules/VREditor/Mono/PlayerSettingsEditorVR.cs @@ -25,7 +25,7 @@ static class Styles public static readonly GUIContent singlepassAndroidWarning2 = EditorGUIUtility.TrTextContent("Multi Pass will be used on Android devices that don't support Single Pass."); public static readonly GUIContent singlepassAndroidWarning3 = EditorGUIUtility.TrTextContent("When using a Scriptable Render Pipeline, Single Pass Double Wide will be used on Android devices that don't support Single Pass Instancing or Multi-view."); public static readonly GUIContent singlePassInstancedWarning = EditorGUIUtility.TrTextContent("Single Pass Instanced is only supported on Windows. Multi Pass will be used on other platforms."); - public static readonly GUIContent multiPassNotSupportedWithSRP = EditorGUIUtility.TrTextContent("Multi Pass is only supported using the legacy render pipelies. Stereo Rendering Mode is set to the fallback mode of Single Pass."); + public static readonly GUIContent multiPassNotSupportedWithSRP = EditorGUIUtility.TrTextContent("Multi Pass is only supported using the legacy render pipelines. Stereo Rendering Mode is set to the fallback mode of Single Pass."); public static readonly GUIContent[] kDefaultStereoRenderingPaths = { @@ -37,6 +37,7 @@ static class Styles public static readonly GUIContent[] kMultiviewStereoRenderingPaths = { EditorGUIUtility.TrTextContent("Multi Pass"), + EditorGUIUtility.TrTextContent("Multiview"), EditorGUIUtility.TrTextContent("Single Pass") }; @@ -61,9 +62,8 @@ static class Styles private SerializedProperty m_AndroidEnableTango; private SerializedProperty m_Enable360StereoCapture; - private bool m_InstallsRequired = false; - private bool m_VuforiaInstalled = false; private bool m_ShowMultiPassSRPInfoBox = false; + private bool m_SharedSettingShown = false; internal int GUISectionIndex { get; set; } @@ -145,11 +145,10 @@ internal void XRSectionGUI(BuildTargetGroup targetGroup, int sectionIndex) } } - // Check to see if any devices require an install and need their GUI hidden - CheckDevicesRequireInstall(targetGroup); - if (m_Settings.BeginSettingsBox(sectionIndex, Styles.xrSettingsTitle)) { + m_SharedSettingShown = false; + if (EditorApplication.isPlaying) { EditorGUILayout.HelpBox("Changing XR Settings is not allowed in play mode.", MessageType.Info); @@ -157,16 +156,16 @@ internal void XRSectionGUI(BuildTargetGroup targetGroup, int sectionIndex) using (new EditorGUI.DisabledScope(EditorApplication.isPlaying)) // switching VR flags in play mode is not supported { - bool shouldVRDeviceSettingsBeDisabled = XRProjectSettings.GetBool(XRProjectSettings.KnownSettings.k_VRDeviceDisabled, false);; + bool shouldVRDeviceSettingsBeDisabled = XRProjectSettings.GetBool(XRProjectSettings.KnownSettings.k_VRDeviceDisabled, false); using (new EditorGUI.DisabledGroupScope(shouldVRDeviceSettingsBeDisabled)) { if (shouldVRDeviceSettingsBeDisabled) { - EditorGUILayout.HelpBox("Legacy XR is currently disabled. Unity has detected that you have one or more XR SDK Provider packages installed. Legacy XR is incompatible with XR SDK. Remove all XR SDK Pacakges from your project to re-enable legacy XR", MessageType.Warning); + EditorGUILayout.HelpBox("Legacy XR is currently disabled. Unity has detected that you have one or more XR SDK Provider packages installed. Legacy XR is incompatible with XR SDK. Remove all XR SDK Packages from your project to re-enable legacy XR", MessageType.Warning); if (!XRProjectSettings.GetBool(XRProjectSettings.KnownSettings.k_VRDeviceDidAlertUser)) { - EditorUtility.DisplayDialog("Legacy XR Disabled", "Unity has detected that you have one or more XR SDK Provider packages installed. Legacy XR is incompatible with XR SDK. Remove all XR SDK Pacakges from your project to re-enable legacy XR", "Ok"); + EditorUtility.DisplayDialog("Legacy XR Disabled", "Unity has detected that you have one or more XR SDK Provider packages installed. Legacy XR is incompatible with XR SDK. Remove all XR SDK Packages from your project to re-enable legacy XR", "Ok"); XRProjectSettings.SetBool(XRProjectSettings.KnownSettings.k_VRDeviceDidAlertUser, true); } } @@ -190,7 +189,11 @@ internal void XRSectionGUI(BuildTargetGroup targetGroup, int sectionIndex) WarnOnGraphicsAPIIncompatibility(targetGroup); } - InstallGUI(targetGroup); + if (m_SharedSettingShown) + { + EditorGUILayout.Space(); + m_Settings.ShowSharedNote(); + } } m_Settings.EndSettingsBox(); } @@ -220,51 +223,6 @@ private void DevicesGUI(BuildTargetGroup targetGroup) } } - private void InstallGUI(BuildTargetGroup targetGroup) - { - if (!m_InstallsRequired) - return; - - EditorGUILayout.Space(); - GUILayout.Label("XR Support Installers", EditorStyles.boldLabel); - EditorGUI.indentLevel++; - - if (!m_VuforiaInstalled) - { - if (EditorGUILayout.LinkLabel("Vuforia Augmented Reality")) - { - string downloadUrl = BuildPlayerWindow.GetPlaybackEngineDownloadURL("Vuforia-AR"); - Application.OpenURL(downloadUrl); - } - } - - EditorGUI.indentLevel--; - EditorGUILayout.Space(); - } - - private void CheckDevicesRequireInstall(BuildTargetGroup targetGroup) - { - // Reset - m_InstallsRequired = false; - - if (!m_VuforiaInstalled) - { - VRDeviceInfoEditor[] deviceInfos = VREditor.GetAllVRDeviceInfo(targetGroup); - - for (int i = 0; i < deviceInfos.Length; ++i) - { - if (deviceInfos[i].deviceNameKey.ToLower() == "vuforia") - { - m_VuforiaInstalled = true; - break; - } - } - - if (!m_VuforiaInstalled) - m_InstallsRequired = true; - } - } - private static GUIContent[] GetStereoRenderingPaths(BuildTargetGroup targetGroup) { if (BuildTargetDiscovery.PlatformGroupHasVRFlag(targetGroup, VRAttributes.SupportStereoMultiviewRendering)) @@ -516,16 +474,6 @@ private float GetVRDeviceElementHeight(BuildTargetGroup target, int index) return list.elementHeight + customOptionsHeight; } - private void SelectVRDeviceElement(BuildTargetGroup target, ReorderableList list) - { - string name = (string)m_VRDeviceActiveUI[target].list[list.index]; - VRCustomOptions customOptions; - if (m_CustomOptions.TryGetValue(name, out customOptions)) - { - customOptions.IsExpanded = false; - } - } - private bool GetVRDeviceElementIsInList(BuildTargetGroup target, string deviceName) { var enabledDevices = VREditor.GetVREnabledDevicesOnTargetGroup(target); @@ -536,6 +484,16 @@ private bool GetVRDeviceElementIsInList(BuildTargetGroup target, string deviceNa return false; } + private void DragVRDeviceElement(BuildTargetGroup target, ReorderableList list) + { + string name = (string)m_VRDeviceActiveUI[target].list[list.index]; + VRCustomOptions customOptions; + if (m_CustomOptions.TryGetValue(name, out customOptions)) + { + customOptions.IsExpanded = false; + } + } + private void VRDevicesGUIOneBuildTarget(BuildTargetGroup targetGroup) { // create reorderable list for this target if needed @@ -548,7 +506,7 @@ private void VRDevicesGUIOneBuildTarget(BuildTargetGroup targetGroup) rlist.drawElementCallback = (rect, index, isActive, isFocused) => DrawVRDeviceElement(targetGroup, rect, index, isActive, isFocused); rlist.drawHeaderCallback = (rect) => GUI.Label(rect, Styles.listHeader, EditorStyles.label); rlist.elementHeightCallback = (index) => GetVRDeviceElementHeight(targetGroup, index); - rlist.onSelectCallback = (list) => SelectVRDeviceElement(targetGroup, list); + rlist.onMouseDragCallback = (list) => DragVRDeviceElement(targetGroup, list); m_VRDeviceActiveUI.Add(targetGroup, rlist); } @@ -579,7 +537,7 @@ private void ErrorOnARDeviceIncompatibility(BuildTargetGroup targetGroup) { if (targetGroup == BuildTargetGroup.Android) { - if (PlayerSettings.Android.ARCoreEnabled && PlayerSettings.GetPlatformVuforiaEnabled(targetGroup)) + if (PlayerSettings.Android.ARCoreEnabled && PlayerSettings.vuforiaEnabled) { EditorGUILayout.HelpBox("Both ARCore and Vuforia XR Device support cannot be selected at the same time. Please select only one XR Device that will manage the Android device.", MessageType.Error); } @@ -590,7 +548,7 @@ private void WarnOnGraphicsAPIIncompatibility(BuildTargetGroup targetGroup) { if (targetGroup == BuildTargetGroup.Android && PlayerSettings.GetGraphicsAPIs(BuildTarget.Android).Contains(UnityEngine.Rendering.GraphicsDeviceType.Vulkan)) { - if (PlayerSettings.Android.ARCoreEnabled || PlayerSettings.GetPlatformVuforiaEnabled(targetGroup) || PlayerSettings.virtualRealitySupported) + if (PlayerSettings.Android.ARCoreEnabled || PlayerSettings.vuforiaEnabled || PlayerSettings.virtualRealitySupported) { EditorGUILayout.HelpBox("XR is currently not supported when using the Vulkan Graphics API.\nPlease go to 'Other Settings' and remove 'Vulkan' from the list of Graphics APIs.", MessageType.Warning); } @@ -608,25 +566,30 @@ internal void TangoGUI(BuildTargetGroup targetGroup) internal void VuforiaGUI(BuildTargetGroup targetGroup) { - if (!BuildTargetDiscovery.PlatformGroupHasVRFlag(targetGroup, VRAttributes.SupportVuforia) - || !m_VuforiaInstalled) + // Vuforia is not supported in the Linux Editor + if (Application.platform == RuntimePlatform.LinuxEditor) return; + if (!BuildTargetDiscovery.PlatformGroupHasVRFlag(targetGroup, VRAttributes.SupportVuforia)) + return; + + m_SharedSettingShown = true; + // Disable toggle when Vuforia is in the VRDevice list and VR Supported == true bool vuforiaEnabled; var shouldDisableScope = VREditor.GetVREnabledOnTargetGroup(targetGroup) && GetVRDeviceElementIsInList(targetGroup, "Vuforia"); using (new EditorGUI.DisabledScope(shouldDisableScope)) { - if (shouldDisableScope && !PlayerSettings.GetPlatformVuforiaEnabled(targetGroup)) // Force Vuforia AR on if Vuforia is in the VRDevice List - PlayerSettings.SetPlatformVuforiaEnabled(targetGroup, true); + if (shouldDisableScope && !PlayerSettings.vuforiaEnabled) // Force Vuforia AR on if Vuforia is in the VRDevice List + PlayerSettings.vuforiaEnabled = true; - vuforiaEnabled = PlayerSettings.GetPlatformVuforiaEnabled(targetGroup); + vuforiaEnabled = PlayerSettings.vuforiaEnabled; EditorGUI.BeginChangeCheck(); - vuforiaEnabled = EditorGUILayout.Toggle(EditorGUIUtility.TrTextContent("Vuforia Augmented Reality Supported"), vuforiaEnabled); + vuforiaEnabled = EditorGUILayout.Toggle(EditorGUIUtility.TrTextContent("Vuforia Augmented Reality Supported*"), vuforiaEnabled); if (EditorGUI.EndChangeCheck()) { - PlayerSettings.SetPlatformVuforiaEnabled(targetGroup, vuforiaEnabled); + PlayerSettings.vuforiaEnabled = vuforiaEnabled; } } diff --git a/Modules/VREditor/Mono/XRPackageSettings.cs b/Modules/VREditor/Mono/XRPackageSettings.cs index 432f186b91..6e03b67d7a 100644 --- a/Modules/VREditor/Mono/XRPackageSettings.cs +++ b/Modules/VREditor/Mono/XRPackageSettings.cs @@ -102,9 +102,7 @@ private void Internal_SaveSettings() return; string packageInitPath = GetStorageFilePath(); - if (!Provider.PromptAndCheckoutIfNeeded( - new string[] { packageInitPath }, - String.Format("Unity needs to update a file ({0}) that is currently under source control.", packageInitPath))) + if (!Provider.PromptAndCheckoutIfNeeded(new string[] { packageInitPath }, String.Empty)) return; FileInfo info = new FileInfo(packageInitPath); @@ -148,9 +146,11 @@ private void Internal_SetSetting(string key, string value) lock (m_SettingsLock) { int index = m_SettingKeys.IndexOf(key); - m_SettingKeys[index] = key; - m_SettingValues[index] = value; - m_IsDirty = true; + if (m_SettingValues[index] != value) + { + m_SettingValues[index] = value; + m_IsDirty = true; + } } } } diff --git a/Modules/VREditor/ScriptBindings/VREditor.bindings.cs b/Modules/VREditor/ScriptBindings/VREditor.bindings.cs index b9f915178d..95cbde8c3d 100644 --- a/Modules/VREditor/ScriptBindings/VREditor.bindings.cs +++ b/Modules/VREditor/ScriptBindings/VREditor.bindings.cs @@ -75,6 +75,22 @@ public static extern bool lowOverheadMode [NativeMethod("SetOculusLowOverheadModeEnabled")] set; } + + public static extern bool protectedContext + { + [NativeMethod("GetOculusProtectedContextEnabled")] + get; + [NativeMethod("SetOculusProtectedContextEnabled")] + set; + } + + public static extern bool v2Signing + { + [NativeMethod("GetOculusV2SigningEnabled")] + get; + [NativeMethod("SetOculusV2SigningEnabled")] + set; + } } [NativeHeader("Runtime/Misc/PlayerSettings.h")] @@ -114,6 +130,18 @@ public static bool lowOverheadMode get { return UnityEditorInternal.PlayerSettingsOculus.lowOverheadMode; } set { UnityEditorInternal.PlayerSettingsOculus.lowOverheadMode = value; } } + + public static bool protectedContext + { + get { return UnityEditorInternal.PlayerSettingsOculus.protectedContext; } + set { UnityEditorInternal.PlayerSettingsOculus.protectedContext = value; } + } + + public static bool v2Signing + { + get { return UnityEditorInternal.PlayerSettingsOculus.v2Signing; } + set { UnityEditorInternal.PlayerSettingsOculus.v2Signing = value; } + } } } diff --git a/Modules/Video/Public/ScriptBindings/MediaComponent.bindings.cs b/Modules/Video/Public/ScriptBindings/MediaComponent.bindings.cs index b983c28f43..3b60697500 100644 --- a/Modules/Video/Public/ScriptBindings/MediaComponent.bindings.cs +++ b/Modules/Video/Public/ScriptBindings/MediaComponent.bindings.cs @@ -11,6 +11,7 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("VideoTesting")] +[assembly: InternalsVisibleTo("Unity.Audio.DSPGraph")] namespace UnityEngineInternal.Video { diff --git a/Modules/Video/Public/ScriptBindings/VideoMediaPlayback.bindings.cs b/Modules/Video/Public/ScriptBindings/VideoMediaPlayback.bindings.cs index 8a60473bfd..02ff07945e 100644 --- a/Modules/Video/Public/ScriptBindings/VideoMediaPlayback.bindings.cs +++ b/Modules/Video/Public/ScriptBindings/VideoMediaPlayback.bindings.cs @@ -9,6 +9,7 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("VideoTesting")] +[assembly: InternalsVisibleTo("Unity.Audio.DSPGraph.Tests")] namespace UnityEngineInternal.Video { diff --git a/Modules/Video/Public/ScriptBindings/VideoPlayerExtensions.bindings.cs b/Modules/Video/Public/ScriptBindings/VideoPlayerExtensions.bindings.cs index f60a2edea6..2e3a8905fa 100644 --- a/Modules/Video/Public/ScriptBindings/VideoPlayerExtensions.bindings.cs +++ b/Modules/Video/Public/ScriptBindings/VideoPlayerExtensions.bindings.cs @@ -31,7 +31,7 @@ public static AudioSampleProvider GetAudioSampleProvider(this VideoPlayer vp, us "Current: " + mode); var provider = AudioSampleProvider.Lookup( - InternalGetAudioSampleProviderId(vp, trackIndex), vp, trackIndex); + vp.InternalGetAudioSampleProviderId(trackIndex), vp, trackIndex); if (provider == null) throw new InvalidOperationException( @@ -49,7 +49,7 @@ public static AudioSampleProvider GetAudioSampleProvider(this VideoPlayer vp, us return provider; } - extern private static uint InternalGetAudioSampleProviderId(VideoPlayer vp, ushort trackIndex); + extern internal static uint InternalGetAudioSampleProviderId(this VideoPlayer vp, ushort trackIndex); } } diff --git a/Modules/VideoEditor/Editor/VideoPlayerEditor.cs b/Modules/VideoEditor/Editor/VideoPlayerEditor.cs index 89fa5cc45c..757f57e88e 100644 --- a/Modules/VideoEditor/Editor/VideoPlayerEditor.cs +++ b/Modules/VideoEditor/Editor/VideoPlayerEditor.cs @@ -45,7 +45,7 @@ class Styles public readonly GUIContent cameraContent = EditorGUIUtility.TrTextContent("Camera", "Camera where the images will be drawn, behind (Back Plane) or in front of (Front Plane) of the scene."); public readonly GUIContent textureContent = - EditorGUIUtility.TrTextContent("Target Texture", "RenderTexture where the images will be drawn. RenderTextures can be created under the Assets folder and the used on other objects."); + EditorGUIUtility.TrTextContent("Target Texture", "RenderTexture where the images will be drawn. RenderTextures can be created under the Assets folder and then used on other objects."); public readonly GUIContent alphaContent = EditorGUIUtility.TrTextContent("Alpha", "A value less than 1.0 will reveal the content behind the video."); public readonly GUIContent camera3DLayout = diff --git a/Modules/XR/ScriptBindings/VRNodeState.cs b/Modules/XR/ScriptBindings/VRNodeState.cs index b83af23df3..7a4d668459 100644 --- a/Modules/XR/ScriptBindings/VRNodeState.cs +++ b/Modules/XR/ScriptBindings/VRNodeState.cs @@ -163,7 +163,7 @@ public bool TryGetAngularAcceleration(out Vector3 angularAcceleration) private bool TryGet(Vector3 inValue, AvailableTrackingData availabilityFlag, out Vector3 outValue) { - if ((m_Tracked == 1) && ((m_AvailableFields & availabilityFlag) > 0)) + if ((m_AvailableFields & availabilityFlag) > 0) { outValue = inValue; return true; @@ -177,7 +177,7 @@ private bool TryGet(Vector3 inValue, AvailableTrackingData availabilityFlag, out private bool TryGet(Quaternion inValue, AvailableTrackingData availabilityFlag, out Quaternion outValue) { - if ((m_Tracked == 1) && ((m_AvailableFields & availabilityFlag) > 0)) + if ((m_AvailableFields & availabilityFlag) > 0) { outValue = inValue; return true; diff --git a/Modules/XR/ScriptBindings/XRInput.bindings.cs b/Modules/XR/ScriptBindings/XRInput.bindings.cs index 661810a1da..1284024c71 100644 --- a/Modules/XR/ScriptBindings/XRInput.bindings.cs +++ b/Modules/XR/ScriptBindings/XRInput.bindings.cs @@ -329,6 +329,7 @@ public bool TryGetFeatureUsages(List featureUsages) public bool TryGetFeatureValue(InputFeatureUsage usage, out Hand value) { return InputDevices.TryGetFeatureValue_XRHand(m_DeviceId, usage.name, out value); } public bool TryGetFeatureValue(InputFeatureUsage usage, out Bone value) { return InputDevices.TryGetFeatureValue_XRBone(m_DeviceId, usage.name, out value); } public bool TryGetFeatureValue(InputFeatureUsage usage, out Eyes value) { return InputDevices.TryGetFeatureValue_XREyes(m_DeviceId, usage.name, out value); } + public bool TryGetFeatureValue(InputFeatureUsage usage, byte[] value) { return InputDevices.TryGetFeatureValue_Custom(m_DeviceId, usage.name, value); } public bool TryGetFeatureValue(InputFeatureUsage usage, out InputTrackingState value) { @@ -713,6 +714,7 @@ private static void InvokeConnectionEvent(UInt64 m_DeviceId, bool connected) internal static extern bool TryGetFeatureValue_Vector2f(UInt64 deviceId, string usage, out Vector2 value); internal static extern bool TryGetFeatureValue_Vector3f(UInt64 deviceId, string usage, out Vector3 value); internal static extern bool TryGetFeatureValue_Quaternionf(UInt64 deviceId, string usage, out Quaternion value); + internal static extern bool TryGetFeatureValue_Custom(UInt64 deviceId, string usage, [Out] byte[] value); internal static extern bool TryGetFeatureValueAtTime_bool(UInt64 deviceId, string usage, Int64 time, out bool value); internal static extern bool TryGetFeatureValueAtTime_UInt32(UInt64 deviceId, string usage, Int64 time, out uint value); diff --git a/Modules/XR/Subsystems/Display/XRDisplaySubsystemDescriptor.bindings.cs b/Modules/XR/Subsystems/Display/XRDisplaySubsystemDescriptor.bindings.cs index b281e08174..c485157e48 100644 --- a/Modules/XR/Subsystems/Display/XRDisplaySubsystemDescriptor.bindings.cs +++ b/Modules/XR/Subsystems/Display/XRDisplaySubsystemDescriptor.bindings.cs @@ -10,6 +10,7 @@ namespace UnityEngine.Experimental.XR { + [NativeHeader("Modules/XR/XRPrefix.h")] [NativeType(Header = "Modules/XR/Subsystems/Display/XRDisplaySubsystemDescriptor.h")] [UsedByNativeCode] public class XRDisplaySubsystemDescriptor : IntegratedSubsystemDescriptor diff --git a/Modules/XREditor/Transition/IVRDeviceSettingsTransition.cs b/Modules/XREditor/Transition/IVRDeviceSettingsTransition.cs new file mode 100644 index 0000000000..4b1d2f8a64 --- /dev/null +++ b/Modules/XREditor/Transition/IVRDeviceSettingsTransition.cs @@ -0,0 +1,14 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using System; + +namespace UnityEditor.XR +{ + internal interface IVRDeviceSettingsTransition + { + void DisableSettings(); + void EnableSettings(); + } +} diff --git a/Modules/XREditor/Transition/VRDeviceSettingsTransitionTargetGroupAttribute.cs b/Modules/XREditor/Transition/VRDeviceSettingsTransitionTargetGroupAttribute.cs new file mode 100644 index 0000000000..86534d9957 --- /dev/null +++ b/Modules/XREditor/Transition/VRDeviceSettingsTransitionTargetGroupAttribute.cs @@ -0,0 +1,26 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using System; +using System.Collections.Generic; + +using UnityEngine; + +using UnityEditor; +using UnityEditorInternal.VR; + +namespace UnityEditor.XR +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)] + internal class VRDeviceSettingsTransitionTargetGroupAttribute : Attribute + { + BuildTargetGroup m_BuildTargetGroup; + + public BuildTargetGroup TargetGroup { get { return m_BuildTargetGroup;} } + public VRDeviceSettingsTransitionTargetGroupAttribute(BuildTargetGroup targetGroup) + { + m_BuildTargetGroup = targetGroup; + } + } +} diff --git a/Modules/XREditor/Transition/VRDeviceTransition.cs b/Modules/XREditor/Transition/VRDeviceTransition.cs index 625982bdbc..9c31bd5256 100644 --- a/Modules/XREditor/Transition/VRDeviceTransition.cs +++ b/Modules/XREditor/Transition/VRDeviceTransition.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Linq; using UnityEditorInternal.VR; using UnityEngine; @@ -66,6 +67,45 @@ static void HandleVRDeviceTransition() } } + static Dictionary s_DeviceSettingsTransitionCache = new Dictionary(); + + static IVRDeviceSettingsTransition GetTypeWithBuildTargetGroupAttribute(BuildTargetGroup targetGroup) + { + IVRDeviceSettingsTransition ret = null; + + if (s_DeviceSettingsTransitionCache.TryGetValue(targetGroup, out ret)) + return ret; + + foreach (var type in TypeCache.GetTypesDerivedFrom()) + { + foreach (var att in type.GetCustomAttributes(typeof(VRDeviceSettingsTransitionTargetGroupAttribute), false)) + { + VRDeviceSettingsTransitionTargetGroupAttribute btgattr = att as VRDeviceSettingsTransitionTargetGroupAttribute; + if (btgattr != null && btgattr.TargetGroup == targetGroup) + { + try + { + ret = Activator.CreateInstance(type) as IVRDeviceSettingsTransition; + } + catch (Exception ex) + { + String logMsg = String.Format("Error getting settings transition instance for buildtarget {0}.\n", targetGroup); + logMsg += ex.Message; + + Debug.LogError(logMsg); + ret = null; + } + if (ret != null) + { + s_DeviceSettingsTransitionCache.Add(targetGroup, ret); + } + } + } + } + + return ret; + } + static void EnableVRSettings() { string storedGroupsTransitioned = ""; @@ -98,6 +138,11 @@ static void EnableVRSettings() Debug.LogFormat("No XR SDK Provider detected in project. Re-enabling VR Device settings for {0}", targetGroup); VREditor.SetVREnabledOnTargetGroup(targetGroup, true); + IVRDeviceSettingsTransition settingsTransition = GetTypeWithBuildTargetGroupAttribute(targetGroup); + if (settingsTransition != null) + { + settingsTransition.EnableSettings(); + } } XRProjectSettings.RemoveSetting(XRProjectSettings.KnownSettings.k_VRDeviceTransitionGroups); @@ -122,6 +167,12 @@ static void DisableVRSettings() if (VREditor.GetVREnabledOnTargetGroup(targetGroup)) { Debug.LogFormat("XR SDK Provider detected in project. Disabling VR Device settings for {0}", targetGroup); + IVRDeviceSettingsTransition settingsTransition = GetTypeWithBuildTargetGroupAttribute(targetGroup); + if (settingsTransition != null) + { + settingsTransition.DisableSettings(); + } + VREditor.SetVREnabledOnTargetGroup(targetGroup, false); didTransitionVRDevice = true; if (!groupsTransitioned.Contains(targetGroupString)) diff --git a/Modules/XREditor/Transition/WindowsMRDeviceSettingsTransition.cs b/Modules/XREditor/Transition/WindowsMRDeviceSettingsTransition.cs new file mode 100644 index 0000000000..24e78f38fb --- /dev/null +++ b/Modules/XREditor/Transition/WindowsMRDeviceSettingsTransition.cs @@ -0,0 +1,41 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using System; +using System.Collections.Generic; + +using UnityEngine; + +using UnityEditor; +using UnityEditorInternal.VR; + +namespace UnityEditor.XR +{ + [VRDeviceSettingsTransitionTargetGroup(BuildTargetGroup.WSA)] + internal class WindowsMRDeviceSettingsTransition : IVRDeviceSettingsTransition + { + internal static readonly string k_WsaRemoting = "WSARemoting"; + + public void DisableSettings() + { + var remotingEnabled = PlayerSettings.GetWsaHolographicRemotingEnabled(); + if (remotingEnabled) + { + PlayerSettings.SetWsaHolographicRemotingEnabled(false); + XRProjectSettings.SetBool(k_WsaRemoting, true); + } + } + + public void EnableSettings() + { + var remotingEnabled = XRProjectSettings.GetBool(k_WsaRemoting); + + if (remotingEnabled) + { + PlayerSettings.SetWsaHolographicRemotingEnabled(remotingEnabled); + XRProjectSettings.RemoveSetting(k_WsaRemoting); + } + } + } +} diff --git a/Projects/CSharp/UnityEditor.csproj b/Projects/CSharp/UnityEditor.csproj index 53aad59722..f92b8164c0 100644 --- a/Projects/CSharp/UnityEditor.csproj +++ b/Projects/CSharp/UnityEditor.csproj @@ -10,7 +10,7 @@ UnityEditor 512 true - 6 + latest false v3.5 @@ -20,10 +20,9 @@ full false ..\..\artifacts\Bee.CSharpSupport\UnityEditor\Debug - COMBINED_ASSEMBLIES;DEBUG;DEBUGGER_LISTENS_FIXED_PORT;ENABLE_ALTERNATIVE_LISTEN_PORT;ENABLE_AR;ENABLE_ASSETPIPELINE_GUI;ENABLE_AUDIO;ENABLE_AUDIO_MANAGER_BASED_SCHEDULING;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_CLOUD_LICENSE;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_SERVICES_COLLAB;ENABLE_CLOUD_SERVICES_COLLAB_SOFTLOCKS;ENABLE_CLOUD_SERVICES_COLLAB_TESTING;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_UNET;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_HOLOLENS_MODULE_API;ENABLE_LZMA;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MICROPHONE;ENABLE_MONO;ENABLE_MONO_BDWGC;ENABLE_MOVIES;ENABLE_MULTIPLE_DISPLAYS;ENABLE_NETWORK;ENABLE_PHYSICS;ENABLE_SCRIPTING_GC_WBARRIERS;ENABLE_TEXTURE_STREAMING;ENABLE_UNET;ENABLE_UNITYEVENTS;ENABLE_UNITYWEBREQUEST;ENABLE_UNITYWEBREQUEST;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_UNLOCKED_DIAGNOSTIC_SWITCHES;ENABLE_VERSION_CONTROL_INTEGRATION;ENABLE_VIDEO;ENABLE_VIDEO;ENABLE_VR;ENABLE_WEBCAM;ENABLE_WEBSOCKET_CLIENT;ENABLE_WWW;INCLUDE_DYNAMIC_GI;PLATFORM_SUPPORTS_MONO;PLAYERCONNECTION_LISTENS_FIXED_PORT;RENDER_SOFTWARE_CURSOR;TRACE;UNITY_ANDROID_API;UNITY_ASSEMBLIES_API;UNITY_ASSERTIONS;UNITY_BJM_API;UNITY_EDITOR;UNITY_EDITOR_API;UNITY_IOS_API;UNITY_LUMIN_API;UNITY_METRO_API;UNITY_PS4_API;UNITY_PS4_API;UNITY_STANDALONE_LINUX_API;UNITY_STANDALONE_OSX_API;UNITY_STANDALONE_WIN_API;UNITY_SWITCH_API;UNITY_TVOS_API;UNITY_WEBGL_API;UNITY_XBOXONE_API + COMBINED_ASSEMBLIES;DEBUG;DEBUGGER_LISTENS_FIXED_PORT;ENABLE_ALTERNATIVE_LISTEN_PORT;ENABLE_AR;ENABLE_ASSETPIPELINE_GUI;ENABLE_AUDIO;ENABLE_AUDIO_MANAGER_BASED_SCHEDULING;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_CLOUD_LICENSE;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_SERVICES_COLLAB;ENABLE_CLOUD_SERVICES_COLLAB_SOFTLOCKS;ENABLE_CLOUD_SERVICES_COLLAB_TESTING;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_UNET;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_HOLOLENS_MODULE_API;ENABLE_LZMA;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MICROPHONE;ENABLE_MONO;ENABLE_MONO_BDWGC;ENABLE_MOVIES;ENABLE_MULTIPLE_DISPLAYS;ENABLE_NETWORK;ENABLE_PHYSICS;ENABLE_SCRIPTING_GC_WBARRIERS;ENABLE_TEXTURE_STREAMING;ENABLE_UNET;ENABLE_UNITYEVENTS;ENABLE_UNITYWEBREQUEST;ENABLE_UNITYWEBREQUEST;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_UNLOCKED_DIAGNOSTIC_SWITCHES;ENABLE_VERSION_CONTROL_INTEGRATION;ENABLE_VIDEO;ENABLE_VIDEO;ENABLE_VR;ENABLE_WEBCAM;ENABLE_WEBSOCKET_CLIENT;ENABLE_WWW;INCLUDE_DYNAMIC_GI;PLATFORM_SUPPORTS_MONO;PLAYERCONNECTION_LISTENS_FIXED_PORT;RENDER_SOFTWARE_CURSOR;TRACE;UNITY_ANDROID_API;UNITY_ASSEMBLIES_API;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_API;UNITY_IOS_API;UNITY_LUMIN_API;UNITY_METRO_API;UNITY_PS4_API;UNITY_STANDALONE_LINUX_API;UNITY_STANDALONE_OSX_API;UNITY_STANDALONE_WIN_API;UNITY_TVOS_API;UNITY_WEBGL_API prompt 4 - true 0169;0649;0626 true @@ -121,9 +120,6 @@ Editor\Mono\BuildPlayerWindowBuildMethods.cs - - Editor\Mono\BuildPlayerWindowPublish.cs - Editor\Mono\BuildTarget.cs @@ -619,9 +615,6 @@ Editor\Mono\SyncProject.cs - - Editor\Mono\SyncRiderProject.cs - Editor\Mono\TagManager.bindings.cs @@ -1210,6 +1203,24 @@ Editor\Mono\CloudBuild\CloudBuild.cs + + Editor\Mono\CodeEditor\CodeEditor.cs + + + Editor\Mono\CodeEditor\CodeEditorProjectSync.cs + + + Editor\Mono\CodeEditor\DefaultExternalCodeEditor.cs + + + Editor\Mono\CodeEditor\ExternalEditor.bindings.cs + + + Editor\Mono\CodeEditor\IExternalCodeEditor.cs + + + Editor\Mono\CodeEditor\SyncVS.cs + Editor\Mono\Collab\AssetAccess.cs @@ -3010,6 +3021,9 @@ Editor\Mono\Scripting\ScriptCompilation\AssetPathVersionMetaData.cs + + Editor\Mono\Scripting\ScriptCompilation\AutoReferencedPackageAssemblies.cs + Editor\Mono\Scripting\ScriptCompilation\CSharpNamespaceParser.cs @@ -3058,6 +3072,9 @@ Editor\Mono\Scripting\ScriptCompilation\MonoLibraryHelpers.cs + + Editor\Mono\Scripting\ScriptCompilation\PlatformSupportModuleHelpers.cs + Editor\Mono\Scripting\ScriptCompilation\PrecompiledAssembly.cs @@ -4231,9 +4248,6 @@ Modules\PackageManager\Editor\Managed\DependencyInfo.cs - - Modules\PackageManager\Editor\Managed\EntitlementsInfo.cs - Modules\PackageManager\Editor\Managed\Error.cs @@ -4879,6 +4893,9 @@ Modules\TilemapEditor\Editor\Managed\EditorPreviewTilemap.cs + + Modules\TilemapEditor\Editor\Managed\Grid\GridPalette.cs + Modules\TilemapEditor\Editor\Managed\TileEditor.cs @@ -5044,6 +5061,9 @@ Modules\UIElementsSamplesEditor\Snippets\LayerMaskFieldSnippet.cs + + Modules\UIElementsSamplesEditor\Snippets\ListViewSnippet.cs + Modules\UIElementsSamplesEditor\Snippets\LongFieldSnippet.cs @@ -5179,9 +5199,18 @@ Modules\XREditor\Build\XRBuildUtilities.bindings.cs + + Modules\XREditor\Transition\IVRDeviceSettingsTransition.cs + + + Modules\XREditor\Transition\VRDeviceSettingsTransitionTargetGroupAttribute.cs + Modules\XREditor\Transition\VRDeviceTransition.cs + + Modules\XREditor\Transition\WindowsMRDeviceSettingsTransition.cs + artifacts\generated\bindings_old\common\ProfilerEditor\ProfilerAPIBindings.gen.cs diff --git a/Projects/CSharp/UnityEngine.csproj b/Projects/CSharp/UnityEngine.csproj index 5cabc48710..7734c32f37 100644 --- a/Projects/CSharp/UnityEngine.csproj +++ b/Projects/CSharp/UnityEngine.csproj @@ -10,7 +10,7 @@ UnityEngine 512 true - 6 + latest false v3.5 @@ -20,10 +20,9 @@ full false ..\..\artifacts\Bee.CSharpSupport\UnityEngine\Debug - COMBINED_ASSEMBLIES;DEBUG;DEBUGGER_LISTENS_FIXED_PORT;ENABLE_ALTERNATIVE_LISTEN_PORT;ENABLE_AR;ENABLE_ASSETPIPELINE_GUI;ENABLE_AUDIO;ENABLE_AUDIO_MANAGER_BASED_SCHEDULING;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_CLOUD_LICENSE;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_SERVICES_COLLAB;ENABLE_CLOUD_SERVICES_COLLAB_SOFTLOCKS;ENABLE_CLOUD_SERVICES_COLLAB_TESTING;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_UNET;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_HOLOLENS_MODULE_API;ENABLE_LZMA;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MICROPHONE;ENABLE_MONO;ENABLE_MONO_BDWGC;ENABLE_MOVIES;ENABLE_MULTIPLE_DISPLAYS;ENABLE_NETWORK;ENABLE_PHYSICS;ENABLE_SCRIPTING_GC_WBARRIERS;ENABLE_TEXTURE_STREAMING;ENABLE_UNET;ENABLE_UNITYEVENTS;ENABLE_UNITYWEBREQUEST;ENABLE_UNITYWEBREQUEST;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_UNLOCKED_DIAGNOSTIC_SWITCHES;ENABLE_VERSION_CONTROL_INTEGRATION;ENABLE_VIDEO;ENABLE_VIDEO;ENABLE_VR;ENABLE_WEBCAM;ENABLE_WEBSOCKET_CLIENT;ENABLE_WWW;INCLUDE_DYNAMIC_GI;PLATFORM_SUPPORTS_MONO;PLAYERCONNECTION_LISTENS_FIXED_PORT;RENDER_SOFTWARE_CURSOR;TRACE;UNITY_ANDROID_API;UNITY_ASSEMBLIES_API;UNITY_ASSERTIONS;UNITY_BJM_API;UNITY_EDITOR;UNITY_EDITOR_API;UNITY_IOS_API;UNITY_LUMIN_API;UNITY_METRO_API;UNITY_PS4_API;UNITY_PS4_API;UNITY_STANDALONE_LINUX_API;UNITY_STANDALONE_OSX_API;UNITY_STANDALONE_WIN_API;UNITY_SWITCH_API;UNITY_TVOS_API;UNITY_WEBGL_API;UNITY_XBOXONE_API + COMBINED_ASSEMBLIES;DEBUG;DEBUGGER_LISTENS_FIXED_PORT;ENABLE_ALTERNATIVE_LISTEN_PORT;ENABLE_AR;ENABLE_ASSETPIPELINE_GUI;ENABLE_AUDIO;ENABLE_AUDIO_MANAGER_BASED_SCHEDULING;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_CLOUD_LICENSE;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_SERVICES_COLLAB;ENABLE_CLOUD_SERVICES_COLLAB_SOFTLOCKS;ENABLE_CLOUD_SERVICES_COLLAB_TESTING;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_UNET;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_HOLOLENS_MODULE_API;ENABLE_LZMA;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MICROPHONE;ENABLE_MONO;ENABLE_MONO_BDWGC;ENABLE_MOVIES;ENABLE_MULTIPLE_DISPLAYS;ENABLE_NETWORK;ENABLE_PHYSICS;ENABLE_SCRIPTING_GC_WBARRIERS;ENABLE_TEXTURE_STREAMING;ENABLE_UNET;ENABLE_UNITYEVENTS;ENABLE_UNITYWEBREQUEST;ENABLE_UNITYWEBREQUEST;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_UNLOCKED_DIAGNOSTIC_SWITCHES;ENABLE_VERSION_CONTROL_INTEGRATION;ENABLE_VIDEO;ENABLE_VIDEO;ENABLE_VR;ENABLE_WEBCAM;ENABLE_WEBSOCKET_CLIENT;ENABLE_WWW;INCLUDE_DYNAMIC_GI;PLATFORM_SUPPORTS_MONO;PLAYERCONNECTION_LISTENS_FIXED_PORT;RENDER_SOFTWARE_CURSOR;TRACE;UNITY_ANDROID_API;UNITY_ASSEMBLIES_API;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_API;UNITY_IOS_API;UNITY_LUMIN_API;UNITY_METRO_API;UNITY_PS4_API;UNITY_STANDALONE_LINUX_API;UNITY_STANDALONE_OSX_API;UNITY_STANDALONE_WIN_API;UNITY_TVOS_API;UNITY_WEBGL_API prompt 4 - true 0626 true @@ -1390,6 +1389,12 @@ Modules\Audio\Public\Managed\Audio.deprecated.cs + + Modules\Audio\Public\Managed\IHandle.cs + + + Modules\Audio\Public\Managed\IValidatable.cs + Modules\Audio\Public\ScriptBindings\Audio.bindings.cs @@ -1420,26 +1425,8 @@ Modules\Audio\Public\ScriptBindings\AudioSourceExtensions.bindings.cs - - Modules\Audio\Public\csas\ScriptBindings\AudioHandle.bindings.cs - - - Modules\Audio\Public\csas\ScriptBindings\DSPCommandBlock.bindings.cs - - - Modules\Audio\Public\csas\ScriptBindings\DSPGraph.bindings.cs - - - Modules\Audio\Public\csas\ScriptBindings\DSPNodeUpdateRequest.bindings.cs - - - Modules\Audio\Public\csas\ScriptBindings\DSPSampleProvider.bindings.cs - - - Modules\Audio\Public\csas\ScriptBindings\ExecuteContext.bindings.cs - - - Modules\Audio\Public\csas\ScriptBindings\ExposeDSPGraph.cs + + Modules\Audio\Public\ScriptBindings\ExposeDSPGraph.cs Modules\Cloth\Cloth.bindings.cs @@ -1450,6 +1437,33 @@ Modules\CrashReporting\CrashReporter.bindings.cs + + Modules\DSPGraph\Public\ScriptBindings\AudioHandle.bindings.cs + + + Modules\DSPGraph\Public\ScriptBindings\AudioMemoryManager.bindings.cs + + + Modules\DSPGraph\Public\ScriptBindings\AudioOutputHookManager.bindings.cs + + + Modules\DSPGraph\Public\ScriptBindings\DSPCommandBlock.bindings.cs + + + Modules\DSPGraph\Public\ScriptBindings\DSPGraph.bindings.cs + + + Modules\DSPGraph\Public\ScriptBindings\DSPNodeUpdateRequest.bindings.cs + + + Modules\DSPGraph\Public\ScriptBindings\DSPSampleProvider.bindings.cs + + + Modules\DSPGraph\Public\ScriptBindings\ExecuteContext.bindings.cs + + + Modules\DSPGraph\Public\ScriptBindings\ExposeDSPGraph.cs + Modules\Director\ScriptBindings\PlayableDirector.bindings.cs diff --git a/README.md b/README.md index 1d348086b4..a5ab2985e4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## Unity 2019.2.0a11 C# reference source code +## Unity 2019.2.23f1 C# reference source code The C# part of the Unity engine and editor source code. May be used for reference purposes only. diff --git a/Runtime/2D/Sorting/ScriptBindings/SortingGroup.bindings.cs b/Runtime/2D/Sorting/ScriptBindings/SortingGroup.bindings.cs index 8ddb72d8f9..330d37223f 100644 --- a/Runtime/2D/Sorting/ScriptBindings/SortingGroup.bindings.cs +++ b/Runtime/2D/Sorting/ScriptBindings/SortingGroup.bindings.cs @@ -14,6 +14,9 @@ namespace UnityEngine.Rendering [NativeType(Header = "Runtime/2D/Sorting/SortingGroup.h")] public sealed partial class SortingGroup : Behaviour { + [StaticAccessor("SortingGroup", StaticAccessorType.DoubleColon)] + internal extern static int invalidSortingGroupID { get; } + public extern string sortingLayerName { get; set; } public extern int sortingLayerID { get; set; } public extern int sortingOrder { get; set; } diff --git a/Runtime/Export/Animation/AnimationCurve.bindings.cs b/Runtime/Export/Animation/AnimationCurve.bindings.cs index 61396f0e52..e7f754f1be 100644 --- a/Runtime/Export/Animation/AnimationCurve.bindings.cs +++ b/Runtime/Export/Animation/AnimationCurve.bindings.cs @@ -98,7 +98,7 @@ public Keyframe(float time, float value, float inTangent, float outTangent, floa // The tangent mode of the keyframe. // This is used only in the editor and will always return 0 in the player. - [Obsolete("Use AnimationUtility.SetLeftTangentMode, AnimationUtility.SetRightTangentMode, AnimationUtility.GetLeftTangentMode or AnimationUtility.GetRightTangentMode instead.")] + [Obsolete("Use AnimationUtility.SetKeyLeftTangentMode, AnimationUtility.SetKeyRightTangentMode, AnimationUtility.GetKeyLeftTangentMode or AnimationUtility.GetKeyRightTangentMode instead.")] public int tangentMode { get { return tangentModeInternal; } set { tangentModeInternal = value; } } internal int tangentModeInternal diff --git a/Runtime/Export/AssemblyInfo.cs b/Runtime/Export/AssemblyInfo.cs index a034cedab6..0318c51825 100644 --- a/Runtime/Export/AssemblyInfo.cs +++ b/Runtime/Export/AssemblyInfo.cs @@ -63,6 +63,8 @@ [assembly: InternalsVisibleTo("UnityEngine.SpriteShapeModule")] [assembly: InternalsVisibleTo("Unity.2D.Sprite.Editor")] [assembly: InternalsVisibleTo("Unity.2D.Sprite.EditorTests")] +[assembly: InternalsVisibleTo("Unity.UI.Builder.Editor")] +[assembly: InternalsVisibleTo("Unity.UI.Builder.EditorTests")] [assembly: InternalsVisibleTo("Unity.InternalAPIEngineBridge.001")] [assembly: InternalsVisibleTo("Unity.InternalAPIEngineBridge.002")] diff --git a/Runtime/Export/Director/IPlayableBehaviour.cs b/Runtime/Export/Director/IPlayableBehaviour.cs index b38a4bc4a4..0f7085ff60 100644 --- a/Runtime/Export/Director/IPlayableBehaviour.cs +++ b/Runtime/Export/Director/IPlayableBehaviour.cs @@ -3,25 +3,31 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; -using System.Reflection; using UnityEngine; -using UnityEngineInternal; -using RequiredByNativeCodeAttribute = UnityEngine.Scripting.RequiredByNativeCodeAttribute; +using UnityEngine.Scripting; namespace UnityEngine.Playables { public interface IPlayableBehaviour { + [RequiredByNativeCode] void OnGraphStart(Playable playable); + [RequiredByNativeCode] void OnGraphStop(Playable playable); + [RequiredByNativeCode] void OnPlayableCreate(Playable playable); + [RequiredByNativeCode] void OnPlayableDestroy(Playable playable); + [RequiredByNativeCode] void OnBehaviourPlay(Playable playable, FrameData info); + [RequiredByNativeCode] void OnBehaviourPause(Playable playable, FrameData info); + [RequiredByNativeCode] void PrepareFrame(Playable playable, FrameData info); + [RequiredByNativeCode] void ProcessFrame(Playable playable, FrameData info, object playerData); } } diff --git a/Runtime/Export/Director/PlayableBehaviour.cs b/Runtime/Export/Director/PlayableBehaviour.cs index 9c9587b55f..4b4f6ee8bf 100644 --- a/Runtime/Export/Director/PlayableBehaviour.cs +++ b/Runtime/Export/Director/PlayableBehaviour.cs @@ -3,10 +3,8 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; -using System.Reflection; using UnityEngine; -using UnityEngineInternal; -using RequiredByNativeCodeAttribute = UnityEngine.Scripting.RequiredByNativeCodeAttribute; +using UnityEngine.Scripting; namespace UnityEngine.Playables { diff --git a/Runtime/Export/Graphics/GraphicsEnums.cs b/Runtime/Export/Graphics/GraphicsEnums.cs index fd074fc7e8..71e6cf80e7 100644 --- a/Runtime/Export/Graphics/GraphicsEnums.cs +++ b/Runtime/Export/Graphics/GraphicsEnums.cs @@ -476,7 +476,7 @@ public enum VRTextureUsage DeviceSpecific } - // keep this in sync with the RenderTextureFlags enum in RenderTexture.h + // keep this in sync with the RenderTextureFlags enum in RenderTextureDesc.h [Flags] public enum RenderTextureCreationFlags { diff --git a/Runtime/Export/Graphics/GraphicsSettings.bindings.cs b/Runtime/Export/Graphics/GraphicsSettings.bindings.cs index 986df7a704..6306a0f977 100644 --- a/Runtime/Export/Graphics/GraphicsSettings.bindings.cs +++ b/Runtime/Export/Graphics/GraphicsSettings.bindings.cs @@ -23,6 +23,7 @@ private GraphicsSettings() {} extern public static bool lightsUseLinearIntensity { get; set; } extern public static bool lightsUseColorTemperature { get; set; } extern public static bool useScriptableRenderPipelineBatching { get; set; } + extern public static bool logWhenShaderIsCompiled { get; set; } extern public static bool HasShaderDefine(GraphicsTier tier, BuiltinShaderDefine defineHash); public static bool HasShaderDefine(BuiltinShaderDefine defineHash) diff --git a/Runtime/Export/Graphics/Texture.cs b/Runtime/Export/Graphics/Texture.cs index 707d48d012..3add42e17c 100644 --- a/Runtime/Export/Graphics/Texture.cs +++ b/Runtime/Export/Graphics/Texture.cs @@ -215,25 +215,25 @@ public RenderTexture(int width, int height, int depth, GraphicsFormat format, in } public RenderTexture(int width, int height, int depth, [uei.DefaultValue("RenderTextureFormat.Default")] RenderTextureFormat format, [uei.DefaultValue("RenderTextureReadWrite.Default")] RenderTextureReadWrite readWrite) - : this(width, height, depth, GraphicsFormatUtility.GetGraphicsFormat(format, readWrite)) + : this(width, height, depth, GetCompatibleFormat(format, readWrite)) { } [uei.ExcludeFromDocs] public RenderTexture(int width, int height, int depth, RenderTextureFormat format) - : this(width, height, depth, GraphicsFormatUtility.GetGraphicsFormat(format, RenderTextureReadWrite.Default)) + : this(width, height, depth, GetCompatibleFormat(format, RenderTextureReadWrite.Default)) { } [uei.ExcludeFromDocs] public RenderTexture(int width, int height, int depth) - : this(width, height, depth, GraphicsFormatUtility.GetGraphicsFormat(RenderTextureFormat.Default, RenderTextureReadWrite.Default)) + : this(width, height, depth, GetCompatibleFormat(RenderTextureFormat.Default, RenderTextureReadWrite.Default)) { } [uei.ExcludeFromDocs] public RenderTexture(int width, int height, int depth, RenderTextureFormat format, int mipCount) - : this(width, height, depth, GraphicsFormatUtility.GetGraphicsFormat(format, RenderTextureReadWrite.Default), mipCount) + : this(width, height, depth, GetCompatibleFormat(format, RenderTextureReadWrite.Default), mipCount) { } diff --git a/Runtime/Export/Math/Vector3.cs b/Runtime/Export/Math/Vector3.cs index cd54bc3914..2c1b253784 100644 --- a/Runtime/Export/Math/Vector3.cs +++ b/Runtime/Export/Math/Vector3.cs @@ -62,7 +62,7 @@ public static Vector3 MoveTowards(Vector3 current, Vector3 target, float maxDist float sqdist = toVector_x * toVector_x + toVector_y * toVector_y + toVector_z * toVector_z; - if (sqdist == 0 || sqdist <= maxDistanceDelta * maxDistanceDelta) + if (sqdist == 0 || (maxDistanceDelta >= 0 && sqdist <= maxDistanceDelta * maxDistanceDelta)) return target; var dist = (float)Math.Sqrt(sqdist); diff --git a/Runtime/Export/Networking/PlayerConnection/ConnectionApi.cs b/Runtime/Export/Networking/PlayerConnection/ConnectionApi.cs index 87a33e8998..191d8b63cc 100644 --- a/Runtime/Export/Networking/PlayerConnection/ConnectionApi.cs +++ b/Runtime/Export/Networking/PlayerConnection/ConnectionApi.cs @@ -44,5 +44,6 @@ public interface IEditorPlayerConnection void RegisterDisconnection(UnityAction callback); void Send(Guid messageId, byte[] data); + bool TrySend(Guid messageId, byte[] data); } } diff --git a/Runtime/Export/Networking/PlayerConnection/PlayerConnection.cs b/Runtime/Export/Networking/PlayerConnection/PlayerConnection.cs index e484100b6b..f3f06e95ee 100644 --- a/Runtime/Export/Networking/PlayerConnection/PlayerConnection.cs +++ b/Runtime/Export/Networking/PlayerConnection/PlayerConnection.cs @@ -115,6 +115,16 @@ public void Send(Guid messageId, byte[] data) GetConnectionNativeApi().SendMessage(messageId, data, 0); } + public bool TrySend(Guid messageId, byte[] data) + { + if (messageId == Guid.Empty) + { + throw new ArgumentException("Cant be Guid.Empty", "messageId"); + } + + return GetConnectionNativeApi().TrySendMessage(messageId, data, 0); + } + public bool BlockUntilRecvMsg(Guid messageId, int timeout) { bool msgReceived = false; diff --git a/Runtime/Export/PlayerConnection/PlayerConnectionInternal.bindings.cs b/Runtime/Export/PlayerConnection/PlayerConnectionInternal.bindings.cs index c98ffd2ca8..5ac7f828a1 100644 --- a/Runtime/Export/PlayerConnection/PlayerConnectionInternal.bindings.cs +++ b/Runtime/Export/PlayerConnection/PlayerConnectionInternal.bindings.cs @@ -12,6 +12,7 @@ internal interface IPlayerEditorConnectionNative void Initialize(); void DisconnectAll(); void SendMessage(Guid messageId, byte[] data, int playerId); + bool TrySendMessage(Guid messageId, byte[] data, int playerId); void Poll(); void RegisterInternal(Guid messageId); void UnregisterInternal(Guid messageId); @@ -31,6 +32,16 @@ void IPlayerEditorConnectionNative.SendMessage(Guid messageId, byte[] data, int SendMessage(messageId.ToString("N"), data, playerId); } + bool IPlayerEditorConnectionNative.TrySendMessage(Guid messageId, byte[] data, int playerId) + { + if (messageId == Guid.Empty) + { + throw new ArgumentException("messageId must not be empty"); + } + + return TrySendMessage(messageId.ToString("N"), data, playerId); + } + void IPlayerEditorConnectionNative.Poll() { PollInternal(); @@ -77,6 +88,10 @@ void IPlayerEditorConnectionNative.DisconnectAll() [FreeFunction("PlayerConnection_Bindings::SendMessage")] extern static void SendMessage(string messageId, byte[] data, int playerId); + //playerId 0 is ANY_PLAYERCONNECTION + [FreeFunction("PlayerConnection_Bindings::TrySendMessage")] + extern static bool TrySendMessage(string messageId, byte[] data, int playerId); + [FreeFunction("PlayerConnection_Bindings::PollInternal")] extern static void PollInternal(); diff --git a/Runtime/Export/RenderPipeline/CullingParameters.cs b/Runtime/Export/RenderPipeline/CullingParameters.cs index 25a71fab5e..89a33f0073 100644 --- a/Runtime/Export/RenderPipeline/CullingParameters.cs +++ b/Runtime/Export/RenderPipeline/CullingParameters.cs @@ -104,6 +104,7 @@ unsafe public struct CameraProperties : IEquatable CoreCameraValues coreCameraValues; uint cameraType; private int projectionIsOblique; + private int isImplicitProjectionMatrix; public Plane GetShadowCullingPlane(int index) { @@ -187,7 +188,7 @@ public bool Equals(CameraProperties other) // m_ShadowCullPlanes == other.m_ShadowCullPlanes // m_CameraCullPlanes == other.m_CameraCullPlanes // layerCullDistances == other.layerCullDistances - return screenRect.Equals(other.screenRect) && viewDir.Equals(other.viewDir) && projectionNear.Equals(other.projectionNear) && projectionFar.Equals(other.projectionFar) && cameraNear.Equals(other.cameraNear) && cameraFar.Equals(other.cameraFar) && cameraAspect.Equals(other.cameraAspect) && cameraToWorld.Equals(other.cameraToWorld) && actualWorldToClip.Equals(other.actualWorldToClip) && cameraClipToWorld.Equals(other.cameraClipToWorld) && cameraWorldToClip.Equals(other.cameraWorldToClip) && implicitProjection.Equals(other.implicitProjection) && stereoWorldToClipLeft.Equals(other.stereoWorldToClipLeft) && stereoWorldToClipRight.Equals(other.stereoWorldToClipRight) && worldToCamera.Equals(other.worldToCamera) && up.Equals(other.up) && right.Equals(other.right) && transformDirection.Equals(other.transformDirection) && cameraEuler.Equals(other.cameraEuler) && velocity.Equals(other.velocity) && farPlaneWorldSpaceLength.Equals(other.farPlaneWorldSpaceLength) && rendererCount == other.rendererCount && baseFarDistance.Equals(other.baseFarDistance) && shadowCullCenter.Equals(other.shadowCullCenter) && layerCullSpherical == other.layerCullSpherical && coreCameraValues.Equals(other.coreCameraValues) && cameraType == other.cameraType && projectionIsOblique == other.projectionIsOblique; + return screenRect.Equals(other.screenRect) && viewDir.Equals(other.viewDir) && projectionNear.Equals(other.projectionNear) && projectionFar.Equals(other.projectionFar) && cameraNear.Equals(other.cameraNear) && cameraFar.Equals(other.cameraFar) && cameraAspect.Equals(other.cameraAspect) && cameraToWorld.Equals(other.cameraToWorld) && actualWorldToClip.Equals(other.actualWorldToClip) && cameraClipToWorld.Equals(other.cameraClipToWorld) && cameraWorldToClip.Equals(other.cameraWorldToClip) && implicitProjection.Equals(other.implicitProjection) && stereoWorldToClipLeft.Equals(other.stereoWorldToClipLeft) && stereoWorldToClipRight.Equals(other.stereoWorldToClipRight) && worldToCamera.Equals(other.worldToCamera) && up.Equals(other.up) && right.Equals(other.right) && transformDirection.Equals(other.transformDirection) && cameraEuler.Equals(other.cameraEuler) && velocity.Equals(other.velocity) && farPlaneWorldSpaceLength.Equals(other.farPlaneWorldSpaceLength) && rendererCount == other.rendererCount && baseFarDistance.Equals(other.baseFarDistance) && shadowCullCenter.Equals(other.shadowCullCenter) && layerCullSpherical == other.layerCullSpherical && coreCameraValues.Equals(other.coreCameraValues) && cameraType == other.cameraType && projectionIsOblique == other.projectionIsOblique && isImplicitProjectionMatrix == other.isImplicitProjectionMatrix; } public override bool Equals(object obj) @@ -243,6 +244,7 @@ public override int GetHashCode() hashCode = (hashCode * 397) ^ coreCameraValues.GetHashCode(); hashCode = (hashCode * 397) ^ (int)cameraType; hashCode = (hashCode * 397) ^ projectionIsOblique; + hashCode = (hashCode * 397) ^ isImplicitProjectionMatrix; return hashCode; } } diff --git a/Runtime/Export/RenderPipeline/ShadowDrawingSettings.cs b/Runtime/Export/RenderPipeline/ShadowDrawingSettings.cs index f258ff8129..1b0848c9e5 100644 --- a/Runtime/Export/RenderPipeline/ShadowDrawingSettings.cs +++ b/Runtime/Export/RenderPipeline/ShadowDrawingSettings.cs @@ -51,6 +51,7 @@ public ShadowDrawingSettings(CullingResults cullingResults, int lightIndex) m_LightIndex = lightIndex; m_UseRenderingLayerMaskTest = 0; m_SplitData = default(ShadowSplitData); + m_SplitData.shadowCascadeBlendCullingFactor = 1f; } public bool Equals(ShadowDrawingSettings other) diff --git a/Runtime/Export/RenderPipeline/ShadowSplitData.cs b/Runtime/Export/RenderPipeline/ShadowSplitData.cs index a0485fd578..a484a7ea21 100644 --- a/Runtime/Export/RenderPipeline/ShadowSplitData.cs +++ b/Runtime/Export/RenderPipeline/ShadowSplitData.cs @@ -19,6 +19,7 @@ unsafe public struct ShadowSplitData : IEquatable // can't make fixed types private, because then the compiler generates different code which BindingsGenerator does not handle yet. internal fixed byte m_CullingPlanes[k_MaximumCullingPlaneCount * Plane.size]; Vector4 m_CullingSphere; + float m_ShadowCascadeBlendCullingFactor; public int cullingPlaneCount { @@ -37,6 +38,17 @@ public Vector4 cullingSphere set { m_CullingSphere = value; } } + public float shadowCascadeBlendCullingFactor + { + get { return m_ShadowCascadeBlendCullingFactor; } + set + { + if (value < 0f || value > 1f) + throw new ArgumentException($"Value should range from {0} to {1}, but was {value}."); + m_ShadowCascadeBlendCullingFactor = value; + } + } + public Plane GetCullingPlane(int index) { if (index < 0 || index >= cullingPlaneCount) diff --git a/Runtime/Export/Scripting/Component.bindings.cs b/Runtime/Export/Scripting/Component.bindings.cs index ed05f0054b..998f674c79 100644 --- a/Runtime/Export/Scripting/Component.bindings.cs +++ b/Runtime/Export/Scripting/Component.bindings.cs @@ -46,6 +46,18 @@ public unsafe T GetComponent() return h.t; } + [TypeInferenceRule(TypeInferenceRules.TypeReferencedByFirstArgument)] + public bool TryGetComponent(Type type, out Component component) + { + return gameObject.TryGetComponent(type, out component); + } + + [System.Security.SecuritySafeCritical] + public unsafe bool TryGetComponent(out T component) + { + return gameObject.TryGetComponent(out component); + } + [FreeFunction(HasExplicitThis = true)] extern public Component GetComponent(string type); diff --git a/Runtime/Export/Scripting/GameObject.bindings.cs b/Runtime/Export/Scripting/GameObject.bindings.cs index 3a59a8e098..1a77875d83 100644 --- a/Runtime/Export/Scripting/GameObject.bindings.cs +++ b/Runtime/Export/Scripting/GameObject.bindings.cs @@ -161,6 +161,29 @@ public T[] GetComponentsInParent() return GetComponentsInParent(false); } + [System.Security.SecuritySafeCritical] + public unsafe bool TryGetComponent(out T component) + { + var h = new CastHelper(); + TryGetComponentFastPath(typeof(T), new System.IntPtr(&h.onePointerFurtherThanT)); + component = h.t; + return h.t != null; + } + + public bool TryGetComponent(Type type, out Component component) + { + component = TryGetComponentInternal(type); + return component != null; + } + + [TypeInferenceRule(TypeInferenceRules.TypeReferencedByFirstArgument)] + [FreeFunction(Name = "GameObjectBindings::TryGetComponentFromType", HasExplicitThis = true, ThrowsException = true)] + internal extern Component TryGetComponentInternal(Type type); + + [FreeFunction(Name = "GameObjectBindings::TryGetComponentFastPath", HasExplicitThis = true, ThrowsException = true)] + [NativeWritableSelf] + internal extern void TryGetComponentFastPath(Type type, IntPtr oneFurtherThanResultValue); + public static GameObject FindWithTag(string tag) { return FindGameObjectWithTag(tag); diff --git a/Runtime/Export/Scripting/RuntimeInitializeOnLoadAttribute.cs b/Runtime/Export/Scripting/RuntimeInitializeOnLoadAttribute.cs index fd1dc128ad..0d13c63e2d 100644 --- a/Runtime/Export/Scripting/RuntimeInitializeOnLoadAttribute.cs +++ b/Runtime/Export/Scripting/RuntimeInitializeOnLoadAttribute.cs @@ -11,7 +11,8 @@ public enum RuntimeInitializeLoadType AfterSceneLoad = 0, BeforeSceneLoad, AfterAssembliesLoaded, - BeforeSplashScreen + BeforeSplashScreen, + SubsystemRegistration }; [Scripting.RequiredByNativeCode] diff --git a/Runtime/Export/Scripting/StackTrace.cs b/Runtime/Export/Scripting/StackTrace.cs index 04e725a918..6a4794dc62 100644 --- a/Runtime/Export/Scripting/StackTrace.cs +++ b/Runtime/Export/Scripting/StackTrace.cs @@ -37,16 +37,6 @@ static public string ExtractStackTrace() return traceString; } - static bool IsSystemStacktraceType(object name) - { - string casted = (string)name; - return casted.StartsWith("UnityEditor.") || - casted.StartsWith("UnityEngine.") || - casted.StartsWith("System.") || - casted.StartsWith("UnityScript.Lang.") || - casted.StartsWith("Boo.Lang."); - } - static public string ExtractStringFromException(System.Object exception) { string message, stackTrace; @@ -97,87 +87,6 @@ static internal void ExtractStringFromExceptionInternal(System.Object exceptiono stackTrace = sb.ToString(); } - [RequiredByNativeCode] - static internal string PostprocessStacktrace(string oldString, bool stripEngineInternalInformation) - { - if (oldString == null) return String.Empty; - string[] split = oldString.Split('\n'); - StringBuilder sb = new StringBuilder(oldString.Length); - for (int i = 0; i < split.Length; i++) - split[i] = split[i].Trim(); - - for (int i = 0; i < split.Length; i++) - { - string newLine = split[i]; - - // Ignore empty lines - if (newLine.Length == 0 || newLine[0] == '\n') - continue; - - // Ignore unmanaged - if (newLine.StartsWith("in (unmanaged)")) - continue; - // Make GameView GUI stack traces skip editor GUI part - if (stripEngineInternalInformation && newLine.StartsWith("UnityEditor.EditorGUIUtility:RenderGameViewCameras")) break; - // Ignore deep system stacktraces - if (stripEngineInternalInformation && i < split.Length - 1 && IsSystemStacktraceType(newLine)) - { - if (IsSystemStacktraceType(split[i + 1])) - continue; - int lineInfo = newLine.IndexOf(" (at"); - if (lineInfo != -1) - newLine = newLine.Substring(0, lineInfo); - } - // Ignore wrapper managed to native - if (newLine.IndexOf("(wrapper managed-to-native)") != -1) - continue; - if (newLine.IndexOf("(wrapper delegate-invoke)") != -1) - continue; - // Ignore unknown method - if (newLine.IndexOf("at <0x00000> ") != -1) - continue; - // Ignore C++ line information - if (stripEngineInternalInformation && newLine.StartsWith("[") && newLine.EndsWith("]")) - continue; - // Ignore starting at - if (newLine.StartsWith("at ")) - { - newLine = newLine.Remove(0, 3); - } - - // Remove square brace [0x00001] - int brace = newLine.IndexOf("[0x"); - int braceClose = -1; - if (brace != -1) - braceClose = newLine.IndexOf("]", brace); - if (brace != -1 && braceClose > brace) - { - newLine = newLine.Remove(brace, braceClose - brace + 1); - } - - newLine = newLine.Replace(" in :0", ""); - newLine = newLine.Replace("\\", "/"); - - if (!string.IsNullOrEmpty(projectFolder)) - newLine = newLine.Replace(projectFolder, ""); - - // Unify path names to unix style - newLine = newLine.Replace('\\', '/'); - - int inStart = newLine.LastIndexOf(" in "); - if (inStart != -1) - { - newLine = newLine.Remove(inStart, 5); - newLine = newLine.Insert(inStart, " (at "); - newLine = newLine.Insert(newLine.Length, ")"); - } - - sb.Append(newLine + "\n"); - } - - return sb.ToString(); - } - [System.Security.SecuritySafeCritical] // System.Diagnostics.StackTrace cannot be accessed from transparent code (PSM, 2.12) static internal string ExtractFormattedStackTrace(StackTrace stackTrace) { diff --git a/Runtime/Export/Scripting/UnitySynchronizationContext.cs b/Runtime/Export/Scripting/UnitySynchronizationContext.cs index 2cc37c0560..26c30119ad 100644 --- a/Runtime/Export/Scripting/UnitySynchronizationContext.cs +++ b/Runtime/Export/Scripting/UnitySynchronizationContext.cs @@ -3,8 +3,9 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; -using System.Threading; using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; using UnityEngine.Scripting; namespace UnityEngine @@ -15,6 +16,7 @@ internal sealed class UnitySynchronizationContext : SynchronizationContext private readonly List m_AsyncWorkQueue; private readonly List m_CurrentFrameWork = new List(kAwqInitialCapacity); private readonly int m_MainThreadID; + private int m_TrackedCount = 0; private UnitySynchronizationContext(int mainThreadID) { @@ -50,6 +52,9 @@ public override void Send(SendOrPostCallback callback, object state) } } + public override void OperationStarted() { Interlocked.Increment(ref m_TrackedCount); } + public override void OperationCompleted() { Interlocked.Decrement(ref m_TrackedCount); } + // Post will add the call to a task list to be executed later on the main thread then work will continue asynchronously public override void Post(SendOrPostCallback callback, object state) { @@ -80,13 +85,17 @@ private void Exec() m_CurrentFrameWork.Clear(); } + private bool HasPendingTasks() + { + return m_AsyncWorkQueue.Count != 0 || m_TrackedCount != 0; + } + // SynchronizationContext must be set before any user code is executed. This is done on // Initial domain load and domain reload at MonoManager ReloadAssembly [RequiredByNativeCode] private static void InitializeSynchronizationContext() { - if (SynchronizationContext.Current == null) - SynchronizationContext.SetSynchronizationContext(new UnitySynchronizationContext(System.Threading.Thread.CurrentThread.ManagedThreadId)); + SynchronizationContext.SetSynchronizationContext(new UnitySynchronizationContext(System.Threading.Thread.CurrentThread.ManagedThreadId)); } // All requests must be processed on the main thread where the full Unity API is available @@ -99,6 +108,32 @@ private static void ExecuteTasks() context.Exec(); } + [RequiredByNativeCode] + private static bool ExecutePendingTasks(long millisecondsTimeout) + { + var context = SynchronizationContext.Current as UnitySynchronizationContext; + if (context == null) + { + return true; + } + + var stopwatch = new Stopwatch(); + stopwatch.Start(); + + while (context.HasPendingTasks()) + { + if (stopwatch.ElapsedMilliseconds > millisecondsTimeout) + { + break; + } + + context.Exec(); + Thread.Sleep(1); + } + + return !context.HasPendingTasks(); + } + private struct WorkRequest { private readonly SendOrPostCallback m_DelagateCallback; diff --git a/Runtime/Export/StaticBatching/CombineForStaticBatching.cs b/Runtime/Export/StaticBatching/CombineForStaticBatching.cs index 42ff36b9aa..d216528821 100644 --- a/Runtime/Export/StaticBatching/CombineForStaticBatching.cs +++ b/Runtime/Export/StaticBatching/CombineForStaticBatching.cs @@ -7,6 +7,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Text; namespace UnityEngine { @@ -14,12 +15,12 @@ public sealed partial class StaticBatchingUtility { static public void Combine(GameObject staticBatchRoot) { - InternalStaticBatchingUtility.CombineRoot(staticBatchRoot); + InternalStaticBatchingUtility.CombineRoot(staticBatchRoot, null); } static public void Combine(GameObject[] gos, GameObject staticBatchRoot) { - InternalStaticBatchingUtility.CombineGameObjects(gos, staticBatchRoot, false); + InternalStaticBatchingUtility.CombineGameObjects(gos, staticBatchRoot, false, null); } } @@ -29,12 +30,12 @@ internal class InternalStaticBatchingUtility const int MaxVerticesInBatch = 64000; // a little bit less than 64K - just in case const string CombinedMeshPrefix = "Combined Mesh"; - static public void CombineRoot(UnityEngine.GameObject staticBatchRoot) + public static void CombineRoot(UnityEngine.GameObject staticBatchRoot, StaticBatcherGOSorter sorter) { - Combine(staticBatchRoot, false, false); + Combine(staticBatchRoot, false, false, sorter); } - static public void Combine(UnityEngine.GameObject staticBatchRoot, bool combineOnlyStatic, bool isEditorPostprocessScene) + static public void Combine(UnityEngine.GameObject staticBatchRoot, bool combineOnlyStatic, bool isEditorPostprocessScene, StaticBatcherGOSorter sorter) { GameObject[] gos = (GameObject[])UnityEngine.Object.FindObjectsOfType(typeof(GameObject)); @@ -53,10 +54,28 @@ static public void Combine(UnityEngine.GameObject staticBatchRoot, bool combineO gos = filteredGos.ToArray(); - CombineGameObjects(gos, staticBatchRoot, isEditorPostprocessScene); + CombineGameObjects(gos, staticBatchRoot, isEditorPostprocessScene, sorter); } - static public void CombineGameObjects(GameObject[] gos, UnityEngine.GameObject staticBatchRoot, bool isEditorPostprocessScene) + public static GameObject[] SortGameObjectsForStaticbatching(GameObject[] gos, StaticBatcherGOSorter sorter) + { + gos = gos.OrderBy(x => + { + Renderer aRenderer = StaticBatcherGOSorter.GetRenderer(x as GameObject); + return sorter.GetMaterialId(aRenderer); + }).ThenBy(y => + { + Renderer aRenderer = StaticBatcherGOSorter.GetRenderer(y as GameObject); + return sorter.GetLightmapIndex(aRenderer); + }).ThenBy(z => + { + Renderer aRenderer = StaticBatcherGOSorter.GetRenderer(z as GameObject); + return sorter.GetRendererId(aRenderer); + }).ToArray(); + return gos; + } + + static public void CombineGameObjects(GameObject[] gos, UnityEngine.GameObject staticBatchRoot, bool isEditorPostprocessScene, StaticBatcherGOSorter sorter) { Matrix4x4 staticBatchInverseMatrix = Matrix4x4.identity; Transform staticBatchRootTransform = null; @@ -70,7 +89,7 @@ static public void CombineGameObjects(GameObject[] gos, UnityEngine.GameObject s int verticesInBatch = 0; List meshes = new List(); - Array.Sort(gos, new SortGO()); + gos = SortGameObjectsForStaticbatching(gos, sorter ?? new StaticBatcherGOSorter()); foreach (GameObject go in gos) { @@ -220,37 +239,24 @@ static private void MakeBatch(List meshe } } - internal class SortGO : IComparer + public class StaticBatcherGOSorter { - int IComparer.Compare(object a, object b) - { - if (a == b) - return 0; - - Renderer aRenderer = GetRenderer(a as GameObject); - Renderer bRenderer = GetRenderer(b as GameObject); - - int compare = GetMaterialId(aRenderer).CompareTo(GetMaterialId(bRenderer)); - if (compare == 0) - compare = GetLightmapIndex(aRenderer).CompareTo(GetLightmapIndex(bRenderer)); - return compare; - } - - static private int GetMaterialId(Renderer renderer) + public virtual long GetMaterialId(Renderer renderer) { if (renderer == null || renderer.sharedMaterial == null) return 0; + return renderer.sharedMaterial.GetInstanceID(); } - static private int GetLightmapIndex(Renderer renderer) + public int GetLightmapIndex(Renderer renderer) { if (renderer == null) return -1; return renderer.lightmapIndex; } - static private Renderer GetRenderer(GameObject go) + public static Renderer GetRenderer(GameObject go) { if (go == null) return null; @@ -260,6 +266,13 @@ static private Renderer GetRenderer(GameObject go) return filter.GetComponent(); } + + public virtual long GetRendererId(Renderer renderer) + { + if (renderer == null) + return -1; + return renderer.GetInstanceID(); + } } } } // namespace UnityEngine diff --git a/Runtime/Export/Time/Time.bindings.cs b/Runtime/Export/Time/Time.bindings.cs index 22eb7f8386..1098056661 100644 --- a/Runtime/Export/Time/Time.bindings.cs +++ b/Runtime/Export/Time/Time.bindings.cs @@ -64,8 +64,21 @@ public class Time [NativeProperty("Realtime")] public static extern float realtimeSinceStartup { get; } - // If /captureFramerate/ is set to a value larger than 0, time will advance in - public static extern int captureFramerate { get; set; } + // If /captureDeltaTime/ is set to a value larger than 0, time will advance by that increment. + public static extern float captureDeltaTime { get; set; } + + // /captureFramerate/ is a convenience (and backwards compatible) accessor for the reciprocal of /captureDeltaTime/ rounded to the nearest integer. + public static int captureFramerate + { + get + { + return captureDeltaTime == 0.0f ? 0 : (int)Mathf.Round(1.0f / captureDeltaTime); + } + set + { + captureDeltaTime = value == 0 ? 0.0f : 1.0f / value; + } + } // Returns true if inside a fixed time step callback such as FixedUpdate, otherwise false. public static extern bool inFixedTimeStep diff --git a/Runtime/Export/TouchScreenKeyboard/TouchScreenKeyboard.bindings.cs b/Runtime/Export/TouchScreenKeyboard/TouchScreenKeyboard.bindings.cs index 82a6ea89e4..131f12bcf1 100644 --- a/Runtime/Export/TouchScreenKeyboard/TouchScreenKeyboard.bindings.cs +++ b/Runtime/Export/TouchScreenKeyboard/TouchScreenKeyboard.bindings.cs @@ -2,7 +2,6 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License - using System; using System.Collections; using UnityEngine.Internal; @@ -21,7 +20,11 @@ internal struct TouchScreenKeyboard_InternalConstructorHelperArguments public int characterLimit; } - public partial class TouchScreenKeyboard + // Interface into the native iPhone, Android, UWP, PS4 and Switch on-screen keyboards - stubbed on other platforms. + [NativeConditional("ENABLE_ONSCREEN_KEYBOARD")] + [NativeHeader("Runtime/Export/TouchScreenKeyboard/TouchScreenKeyboard.bindings.h")] + [NativeHeader("Runtime/Input/KeyboardOnScreen.h")] + public class TouchScreenKeyboard { // The status of the on-screen keyboard public enum Status @@ -35,13 +38,7 @@ public enum Status // The on-screen keyboard was closed by touching outside of the keyboard. LostFocus = 3, }; - } - // Interface into the native iPhone, Android, Windows Phone and Switch on-screen keyboards - it is not available on other platforms. - [NativeHeader("Runtime/Export/TouchScreenKeyboard/TouchScreenKeyboard.bindings.h")] - [NativeHeader("Runtime/Input/KeyboardOnScreen.h")] - public partial class TouchScreenKeyboard - { // We are matching the KeyboardOnScreen class here so we can directly // access it. [System.NonSerialized] @@ -83,7 +80,6 @@ public TouchScreenKeyboard(string text, TouchScreenKeyboardType keyboardType, bo [FreeFunction("TouchScreenKeyboard_InternalConstructorHelper")] private static extern IntPtr TouchScreenKeyboard_InternalConstructorHelper(ref TouchScreenKeyboard_InternalConstructorHelperArguments arguments, string text, string textPlaceholder); - public static bool isSupported { get @@ -195,8 +191,8 @@ public static TouchScreenKeyboard Open(string text) return Open(text, keyboardType, autocorrection, multiline, secure, alert, textPlaceholder, characterLimit); } - // Returns the text displayed by the input field of the keyboard. This - extern public string text + // Returns the text displayed by the input field of the keyboard. + public extern string text { [NativeName("GetText")] get; @@ -204,8 +200,8 @@ extern public string text set; } - // Specifies if text input field above the keyboard will be hidden when - extern public static bool hideInput + // Specifies if text input field above the keyboard will be hidden when the keyboard is on screen. + public static extern bool hideInput { [NativeName("IsInputHidden")] get; @@ -213,8 +209,8 @@ extern public static bool hideInput set; } - // Specifies if the keyboard is visible or is sliding into the position on - extern public bool active + // Specifies if the keyboard is visible or is sliding into the position on screen. + public extern bool active { [NativeName("IsActive")] get; @@ -223,7 +219,7 @@ extern public bool active } [FreeFunction("TouchScreenKeyboard_GetDone")] - extern private static bool GetDone(IntPtr ptr); + private static extern bool GetDone(IntPtr ptr); // Specifies if input process was finished (RO) [Obsolete("Property done is deprecated, use status instead")] @@ -233,7 +229,7 @@ public bool done } [FreeFunction("TouchScreenKeyboard_GetWasCanceled")] - extern private static bool GetWasCanceled(IntPtr ptr); + private static extern bool GetWasCanceled(IntPtr ptr); // Specifies if input process was canceled (RO) [Obsolete("Property wasCanceled is deprecated, use status instead.")] @@ -243,14 +239,14 @@ public bool wasCanceled } // Returns the status of the touch screen keyboard (RO). See [[TouchScreenKeyboard.Status]] enumeration for possible values. - extern public Status status + public extern Status status { [NativeName("GetKeyboardStatus")] get; } // Set character limit for keyboard input - extern public int characterLimit + public extern int characterLimit { [NativeName("GetCharacterLimit")] get; @@ -286,9 +282,9 @@ public RangeInt selection } } - extern private static void GetSelection(out int start, out int length); + private static extern void GetSelection(out int start, out int length); - extern private static void SetSelection(int start, int length); + private static extern void SetSelection(int start, int length); // Returns the type of keyboard being displayed. (RO) public TouchScreenKeyboardType type @@ -303,15 +299,16 @@ public int targetDisplay set {} } - // Returns portion of the screen which is covered by the keyboard. Returns - extern public static Rect area + // Returns portion of the screen which is covered by the keyboard. + [NativeConditional("ENABLE_ONSCREEN_KEYBOARD", "RectT()")] + public static extern Rect area { [NativeName("GetRect")] get; } // Returns true whenever any keyboard is completely visible on the screen. - extern public static bool visible + public static extern bool visible { [NativeName("IsVisible")] get; diff --git a/Runtime/Export/TouchScreenKeyboard/TouchScreenKeyboardType.cs b/Runtime/Export/TouchScreenKeyboard/TouchScreenKeyboardType.cs index ba93dc8275..200cd4d4ef 100644 --- a/Runtime/Export/TouchScreenKeyboard/TouchScreenKeyboardType.cs +++ b/Runtime/Export/TouchScreenKeyboard/TouchScreenKeyboardType.cs @@ -29,6 +29,8 @@ public enum TouchScreenKeyboardType // Keyboard with symbol keys often used on social media such as Twitter, features the "@" (and "#" on iOS/tvOS) Social = 9, // Keyboard optimized for search terms, features the space and "." - Search = 10 + Search = 10, + // Keyboard with numbers and a decimal point. + DecimalPad = 11 } } diff --git a/Runtime/Export/UnityEvent/UnityEvent.cs b/Runtime/Export/UnityEvent/UnityEvent.cs index f0edc3e3c1..ef19ca5cb0 100644 --- a/Runtime/Export/UnityEvent/UnityEvent.cs +++ b/Runtime/Export/UnityEvent/UnityEvent.cs @@ -689,9 +689,6 @@ public abstract class UnityEventBase : ISerializationCallbackReceiver [SerializeField] private PersistentCallGroup m_PersistentCalls; -#pragma warning disable 414, CS0169 //used by serialized properties - [SerializeField] private string m_TypeName; - // Dirtying can happen outside of MainThread, but we need to rebuild on the MainThread. private bool m_CallsDirty = true; @@ -699,7 +696,6 @@ protected UnityEventBase() { m_Calls = new InvokableCallList(); m_PersistentCalls = new PersistentCallGroup(); - m_TypeName = GetType().AssemblyQualifiedName; } void ISerializationCallbackReceiver.OnBeforeSerialize() @@ -708,7 +704,6 @@ void ISerializationCallbackReceiver.OnBeforeSerialize() void ISerializationCallbackReceiver.OnAfterDeserialize() { DirtyPersistentCalls(); - m_TypeName = GetType().AssemblyQualifiedName; } protected abstract MethodInfo FindMethod_Impl(string name, object targetObj); diff --git a/Runtime/Export/Unsafe/UnsafeUtilityPatched.cs b/Runtime/Export/Unsafe/UnsafeUtilityPatched.cs index 36d95d2996..dbcac70ce4 100644 --- a/Runtime/Export/Unsafe/UnsafeUtilityPatched.cs +++ b/Runtime/Export/Unsafe/UnsafeUtilityPatched.cs @@ -13,14 +13,30 @@ namespace Unity.Collections.LowLevel.Unsafe public static partial class UnsafeUtility { // Copies sizeof(T) bytes from ptr to output + [MethodImpl(256)] // AggressiveInlining unsafe public static void CopyPtrToStructure(void* ptr, out T output) where T : struct + { + if (ptr == null) + throw new ArgumentNullException(); + InternalCopyPtrToStructure(ptr, out output); + } + + unsafe static void InternalCopyPtrToStructure(void* ptr, out T output) where T : struct { // @patched at compile time throw new NotImplementedException("Patching this method failed"); } // Copies sizeof(T) bytes from output to ptr + [MethodImpl(256)] // AggressiveInlining unsafe public static void CopyStructureToPtr(ref T input, void* ptr) where T : struct + { + if (ptr == null) + throw new ArgumentNullException(); + InternalCopyStructureToPtr(ref input, ptr); + } + + unsafe static void InternalCopyStructureToPtr(ref T input, void* ptr) where T : struct { // @patched at compile time throw new NotImplementedException("Patching this method failed"); diff --git a/Runtime/Export/WSA/WSAApplication.bindings.cs b/Runtime/Export/WSA/WSAApplication.bindings.cs index fff84ef584..263ccbee4d 100644 --- a/Runtime/Export/WSA/WSAApplication.bindings.cs +++ b/Runtime/Export/WSA/WSAApplication.bindings.cs @@ -4,6 +4,7 @@ using System; using UnityEngine.Bindings; +using UnityEngine.Scripting; namespace UnityEngine.WSA { @@ -49,12 +50,14 @@ public static string advertisingIdentifier private static extern string GetAppArguments(); + [RequiredByNativeCode] internal static void InvokeWindowSizeChangedEvent(int width, int height) { if (windowSizeChanged != null) windowSizeChanged.Invoke(width, height); } + [RequiredByNativeCode] internal static void InvokeWindowActivatedEvent(WindowActivationState state) { if (windowActivated != null) windowActivated.Invoke(state); diff --git a/Runtime/Profiler/ScriptBindings/Profiler.bindings.cs b/Runtime/Profiler/ScriptBindings/Profiler.bindings.cs index 34abcaf01b..5577a2167b 100644 --- a/Runtime/Profiler/ScriptBindings/Profiler.bindings.cs +++ b/Runtime/Profiler/ScriptBindings/Profiler.bindings.cs @@ -40,6 +40,7 @@ public enum ProfilerArea [NativeHeader("Runtime/Utilities/MemoryUtilities.h")] public sealed class Profiler { + internal const uint invalidProfilerArea = ~0u; // This class can't be explicitly created private Profiler() {} @@ -148,6 +149,7 @@ public static void BeginThreadProfiling(string threadGroupName, string threadNam [Conditional("ENABLE_PROFILER")] public static void BeginSample(string name) { + ValidateArguments(name); BeginSampleImpl(name, null); } @@ -158,9 +160,19 @@ public static void BeginSample(string name) [Conditional("ENABLE_PROFILER")] public static void BeginSample(string name, Object targetObject) { + ValidateArguments(name); BeginSampleImpl(name, targetObject); } + [MethodImpl(256)] + static void ValidateArguments(string name) + { + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentException("Argument should be a valid string.", "name"); + } + } + [NativeMethod(Name = "ProfilerBindings::BeginSample", IsFreeFunction = true, IsThreadSafe = true)] private extern static void BeginSampleImpl(string name, Object targetObject); diff --git a/Runtime/Profiler/ScriptBindings/Sampler.bindings.cs b/Runtime/Profiler/ScriptBindings/Sampler.bindings.cs index 7122bc043d..4ba7b725e8 100644 --- a/Runtime/Profiler/ScriptBindings/Sampler.bindings.cs +++ b/Runtime/Profiler/ScriptBindings/Sampler.bindings.cs @@ -105,7 +105,6 @@ public void Begin(UnityEngine.Object targetObject) BeginWithObject(targetObject); } - [Conditional("ENABLE_PROFILER")] [NativeMethod(Name = "ProfilerBindings::CustomSampler_BeginWithObject", IsFreeFunction = true, HasExplicitThis = true, IsThreadSafe = true)] private extern void BeginWithObject(UnityEngine.Object targetObject); diff --git a/Runtime/Transform/ScriptBindings/TransformAccessArray.bindings.cs b/Runtime/Transform/ScriptBindings/TransformAccessArray.bindings.cs index 6d487ef84f..228bbbca47 100644 --- a/Runtime/Transform/ScriptBindings/TransformAccessArray.bindings.cs +++ b/Runtime/Transform/ScriptBindings/TransformAccessArray.bindings.cs @@ -27,6 +27,9 @@ public partial struct TransformAccess public Quaternion localRotation { get { Quaternion r; GetLocalRotation(ref this, out r); return r; } set { SetLocalRotation(ref this, ref value); } } public Vector3 localScale { get { Vector3 s; GetLocalScale(ref this, out s); return s; } set { SetLocalScale(ref this, ref value); } } + public Matrix4x4 localToWorldMatrix { get { Matrix4x4 m; GetLocalToWorldMatrix(ref this, out m); return m; } } + public Matrix4x4 worldToLocalMatrix { get { Matrix4x4 m; GetWorldToLocalMatrix(ref this, out m); return m; } } + //@TODO: Static code analysis needs to prevent creation of TransformAccess except through TransformAccessArray accessor. // Code below assumes this to be true since it doesn't check if TransformAccess is valid @@ -62,6 +65,12 @@ public partial struct TransformAccess [NativeMethod(Name = "TransformAccessBindings::SetLocalScale", IsThreadSafe = true, IsFreeFunction = true)] private static extern void SetLocalScale(ref TransformAccess access, ref Vector3 r); + [NativeMethod(Name = "TransformAccessBindings::GetLocalToWorldMatrix", IsThreadSafe = true, IsFreeFunction = true)] + private static extern void GetLocalToWorldMatrix(ref TransformAccess access, out Matrix4x4 m); + + [NativeMethod(Name = "TransformAccessBindings::GetWorldToLocalMatrix", IsThreadSafe = true, IsFreeFunction = true)] + private static extern void GetWorldToLocalMatrix(ref TransformAccess access, out Matrix4x4 m); + //@TODO: API incomplete... } diff --git a/Tools/Unity.CecilTools/Unity.CecilTools.gen.csproj b/Tools/Unity.CecilTools/Unity.CecilTools.gen.csproj index 9a4fcc7297..54eb96e02c 100644 --- a/Tools/Unity.CecilTools/Unity.CecilTools.gen.csproj +++ b/Tools/Unity.CecilTools/Unity.CecilTools.gen.csproj @@ -10,7 +10,7 @@ Unity.CecilTools 512 true - 6 + latest false v3.5 @@ -23,7 +23,6 @@ DEBUG;TRACE prompt 4 - true 1702 false diff --git a/Tools/Unity.SerializationLogic/Unity.SerializationLogic.gen.csproj b/Tools/Unity.SerializationLogic/Unity.SerializationLogic.gen.csproj index 2175135dd2..d11f549420 100644 --- a/Tools/Unity.SerializationLogic/Unity.SerializationLogic.gen.csproj +++ b/Tools/Unity.SerializationLogic/Unity.SerializationLogic.gen.csproj @@ -10,7 +10,7 @@ Unity.SerializationLogic 512 true - 6 + latest false v3.5 @@ -23,7 +23,6 @@ DEBUG;TRACE prompt 4 - true 1702 false diff --git a/artifacts/generated/bindings_old/common/Editor/AssetDatabaseBindings.gen.cs b/artifacts/generated/bindings_old/common/Editor/AssetDatabaseBindings.gen.cs index 76ff53969f..ba3690355a 100644 --- a/artifacts/generated/bindings_old/common/Editor/AssetDatabaseBindings.gen.cs +++ b/artifacts/generated/bindings_old/common/Editor/AssetDatabaseBindings.gen.cs @@ -517,45 +517,6 @@ public static void ExportPackage (string[] assetPathNames, string fileName) { ExportPackage ( assetPathNames, fileName, flags ); } - public static void ImportPackage(string packagePath, bool interactive) - { - if (string.IsNullOrEmpty(packagePath)) - throw new ArgumentException("Path can not be empty or null", "packagePath"); - - string packageIconPath; - bool canPerformReInstall; - ImportPackageItem[] items = PackageUtility.ExtractAndPrepareAssetList(packagePath, out packageIconPath, out canPerformReInstall); - - if (items == null) - return; - - if (interactive) - PackageImport.ShowImportPackage(packagePath, items, packageIconPath, canPerformReInstall); - else - { - string packageName = System.IO.Path.GetFileNameWithoutExtension(packagePath); - PackageUtility.ImportPackageAssets(packageName, items, false); - } - } - - - internal static void ImportPackageImmediately(string packagePath) - { - if (string.IsNullOrEmpty(packagePath)) - throw new ArgumentException("Path can not be empty or null", "packagePath"); - - string packageIconPath; - bool canPerformReInstall; - ImportPackageItem[] items = PackageUtility.ExtractAndPrepareAssetList(packagePath, out packageIconPath, out canPerformReInstall); - - if (items == null || items.Length == 0) - return; - - string packageName = System.IO.Path.GetFileNameWithoutExtension(packagePath); - PackageUtility.ImportPackageAssetsImmediately(packageName, items, false); - } - - [UnityEngine.Scripting.GeneratedByOldBindingsGeneratorAttribute] // Temporarily necessary for bindings migration [System.Runtime.CompilerServices.MethodImplAttribute((System.Runtime.CompilerServices.MethodImplOptions)0x1000)] extern internal static string GetUniquePathNameAtSelectedPath (string fileName) ; diff --git a/artifacts/generated/bindings_old/common/Editor/EditorConnectionInternalBindings.gen.cs b/artifacts/generated/bindings_old/common/Editor/EditorConnectionInternalBindings.gen.cs index c16d9c90b9..66e9fbaf79 100644 --- a/artifacts/generated/bindings_old/common/Editor/EditorConnectionInternalBindings.gen.cs +++ b/artifacts/generated/bindings_old/common/Editor/EditorConnectionInternalBindings.gen.cs @@ -28,11 +28,20 @@ void IPlayerEditorConnectionNative.SendMessage(Guid messageId, byte[] data, int { if (messageId == Guid.Empty) { - throw new ArgumentException("messageId must not be empty"); + throw new ArgumentException(nameof(messageId) + " must not be empty"); } SendMessage(messageId.ToString("N"), data, playerId); } + bool IPlayerEditorConnectionNative.TrySendMessage(Guid messageId, byte[] data, int playerId) + { + if (messageId == Guid.Empty) + { + throw new ArgumentException(nameof(messageId) + " must not be empty"); + } + return TrySendMessage(messageId.ToString("N"), data, playerId); + } + void IPlayerEditorConnectionNative.Poll() { PollInternal(); @@ -80,6 +89,10 @@ public bool IsConnected() [System.Runtime.CompilerServices.MethodImplAttribute((System.Runtime.CompilerServices.MethodImplOptions)0x1000)] extern public static void SendMessage (string messageId, byte[] data, int playerId) ; + [UnityEngine.Scripting.GeneratedByOldBindingsGeneratorAttribute] // Temporarily necessary for bindings migration + [System.Runtime.CompilerServices.MethodImplAttribute((System.Runtime.CompilerServices.MethodImplOptions)0x1000)] + extern public static bool TrySendMessage (string messageId, byte[] data, int playerId) ; + [UnityEngine.Scripting.GeneratedByOldBindingsGeneratorAttribute] // Temporarily necessary for bindings migration [System.Runtime.CompilerServices.MethodImplAttribute((System.Runtime.CompilerServices.MethodImplOptions)0x1000)] extern public static void PollInternal () ;