diff --git a/Editor/Mono/2D/Common/ScriptBindings/SpriteEditorExtension.bindings.cs b/Editor/Mono/2D/Common/ScriptBindings/SpriteEditorExtension.bindings.cs index 9f28f148e2..60edc83628 100644 --- a/Editor/Mono/2D/Common/ScriptBindings/SpriteEditorExtension.bindings.cs +++ b/Editor/Mono/2D/Common/ScriptBindings/SpriteEditorExtension.bindings.cs @@ -3,11 +3,10 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using UnityEngine; -using UnityEditor; using UnityEngine.Bindings; using UnityEngine.U2D; -namespace UnityEditor.Experimental.U2D +namespace UnityEditor.U2D { [NativeHeader("Editor/Src/2D/SpriteEditorExtension.h")] public static class SpriteEditorExtension diff --git a/Editor/Mono/Animation/AnimationMode.bindings.cs b/Editor/Mono/Animation/AnimationMode.bindings.cs index d74f4cc0d8..cf8530ffa3 100644 --- a/Editor/Mono/Animation/AnimationMode.bindings.cs +++ b/Editor/Mono/Animation/AnimationMode.bindings.cs @@ -181,6 +181,15 @@ internal static void StartAnimationRecording() [NativeThrows] extern internal static void RevertPropertyModificationsForObject([NotNull] Object target); + // Returns editor curve bindings for animation clip and animator hierarchy that need to be snapshot for animation mode. + extern internal static EditorCurveBinding[] GetAllBindings([NotNull] GameObject root, [NotNull] AnimationClip clip); + + // Returns editor curve bindings for animation clip that need to be snapshot for animation mode. + extern internal static EditorCurveBinding[] GetCurveBindings([NotNull] AnimationClip clip); + + // Return editor curve bindings for animator hierarhcy that need to be snapshot for animation mode. + extern internal static EditorCurveBinding[] GetAnimatorBindings([NotNull] GameObject root); + extern private static bool Internal_InAnimationMode(Object driver); extern private static bool Internal_InAnimationModeNoDriver(); diff --git a/Editor/Mono/Animation/AnimationUtility.bindings.cs b/Editor/Mono/Animation/AnimationUtility.bindings.cs index 8c3c0f0a84..65d1f17da4 100644 --- a/Editor/Mono/Animation/AnimationUtility.bindings.cs +++ b/Editor/Mono/Animation/AnimationUtility.bindings.cs @@ -143,11 +143,6 @@ internal static EditorCurveBinding[] GetAnimatableBindings(ScriptableObject scri return Internal_GetScriptableObjectAnimatableBindings(scriptableObject); } - internal static EditorCurveBinding[] GetAdditionalAnimatorBindings(GameObject targetObject) - { - return Internal_GetAdditionalAnimatorBindings(targetObject); - } - internal static EditorCurveBinding[] GetAnimationStreamBindings(GameObject root) { return Internal_GetAnimationStreamBindings(root); @@ -155,7 +150,6 @@ internal static EditorCurveBinding[] GetAnimationStreamBindings(GameObject root) extern private static EditorCurveBinding[] Internal_GetGameObjectAnimatableBindings([NotNull] GameObject targetObject, [NotNull] GameObject root); extern private static EditorCurveBinding[] Internal_GetScriptableObjectAnimatableBindings([NotNull] ScriptableObject scriptableObject); - extern private static EditorCurveBinding[] Internal_GetAdditionalAnimatorBindings([NotNull] GameObject targetObject); extern private static EditorCurveBinding[] Internal_GetAnimationStreamBindings([NotNull] GameObject root); // Binds the property and returns the type of the bound value (Can be used to display special UI for it and to enforce correct drag and drop) diff --git a/Editor/Mono/Animation/AnimationWindow/AnimationWindow.cs b/Editor/Mono/Animation/AnimationWindow/AnimationWindow.cs index cac5c48201..fbddcca9f8 100644 --- a/Editor/Mono/Animation/AnimationWindow/AnimationWindow.cs +++ b/Editor/Mono/Animation/AnimationWindow/AnimationWindow.cs @@ -179,9 +179,6 @@ static bool OnOpenAsset(int instanceID, int line) public bool EditGameObject(GameObject gameObject) { - if (state.linkedWithSequencer == true) - return false; - return EditGameObjectInternal(gameObject, (IAnimationWindowControl)null); } @@ -268,6 +265,9 @@ private bool ShouldUpdateGameObjectSelection(GameObjectSelectionItem selectedIte if (m_LockTracker.isLocked) return false; + if (state.linkedWithSequencer) + return false; + // Selected game object with no animation player. if (selectedItem.rootGameObject == null) return true; diff --git a/Editor/Mono/Animation/AnimationWindow/AnimationWindowHierarchyGUI.cs b/Editor/Mono/Animation/AnimationWindow/AnimationWindowHierarchyGUI.cs index cc771c57f1..9371b950c0 100644 --- a/Editor/Mono/Animation/AnimationWindow/AnimationWindowHierarchyGUI.cs +++ b/Editor/Mono/Animation/AnimationWindow/AnimationWindowHierarchyGUI.cs @@ -304,15 +304,6 @@ private string GetGameObjectName(GameObject rootGameObject, string path) return splits[splits.Length - 1]; } - private string GetPathWithoutChildmostGameObject(string path) - { - if (string.IsNullOrEmpty(path)) - return ""; - - int lastIndex = path.LastIndexOf('/'); - return path.Substring(0, lastIndex + 1); - } - private void DoValueField(Rect rect, AnimationWindowHierarchyNode node, int row) { bool curvesChanged = false; diff --git a/Editor/Mono/Animation/AnimationWindow/AnimationWindowState.cs b/Editor/Mono/Animation/AnimationWindow/AnimationWindowState.cs index 19398dbf62..f99df8e428 100644 --- a/Editor/Mono/Animation/AnimationWindow/AnimationWindowState.cs +++ b/Editor/Mono/Animation/AnimationWindow/AnimationWindowState.cs @@ -900,15 +900,6 @@ public void SelectKey(AnimationWindowKeyframe keyframe) m_SelectionBoundsCache = null; } - public void SelectKeysFromDopeline(DopeLine dopeline) - { - if (dopeline == null) - return; - - foreach (var key in dopeline.keys) - SelectKey(key); - } - public void UnselectKey(AnimationWindowKeyframe keyframe) { int hash = keyframe.GetHash(); @@ -919,15 +910,6 @@ public void UnselectKey(AnimationWindowKeyframe keyframe) m_SelectionBoundsCache = null; } - public void UnselectKeysFromDopeline(DopeLine dopeline) - { - if (dopeline == null) - return; - - foreach (var key in dopeline.keys) - UnselectKey(key); - } - public void DeleteSelectedKeys() { if (selectedKeys.Count == 0) @@ -1546,18 +1528,6 @@ public HashSet GetAffectedHierarchyIDs(List keyfra return hierarchyIDs; } - public List GetAffectedDopelines(List keyframes) - { - List affectedDopelines = new List(); - - foreach (AnimationWindowCurve curve in GetAffectedCurves(keyframes)) - foreach (DopeLine dopeline in dopelines) - if (!affectedDopelines.Contains(dopeline) && dopeline.curves.Contains(curve)) - affectedDopelines.Add(dopeline); - - return affectedDopelines; - } - public List GetAffectedCurves(List keyframes) { List affectedCurves = new List(); diff --git a/Editor/Mono/Animation/AnimationWindow/AnimationWindowStyles.cs b/Editor/Mono/Animation/AnimationWindow/AnimationWindowStyles.cs index a8db5f8fe6..cb785b822a 100644 --- a/Editor/Mono/Animation/AnimationWindow/AnimationWindowStyles.cs +++ b/Editor/Mono/Animation/AnimationWindow/AnimationWindowStyles.cs @@ -22,7 +22,7 @@ internal class AnimationWindowStyles public static GUIContent addKeyframeContent = EditorGUIUtility.TrIconContent("Animation.AddKeyframe", "Add keyframe."); public static GUIContent addEventContent = EditorGUIUtility.TrIconContent("Animation.AddEvent", "Add event."); public static GUIContent filterBySelectionContent = EditorGUIUtility.TrIconContent("Animation.FilterBySelection", "Filter by selection."); - public static GUIContent sequencerLinkContent = EditorGUIUtility.TrIconContent("Animation.SequencerLink", "Animation Window is linked to Sequence Editor. Press to Unlink."); + public static GUIContent sequencerLinkContent = EditorGUIUtility.TrIconContent("Animation.SequencerLink", "Animation Window is linked to Timeline Editor. Press to Unlink."); public static GUIContent noAnimatableObjectSelectedText = EditorGUIUtility.TrTextContent("No animatable object selected."); public static GUIContent formatIsMissing = EditorGUIUtility.TrTextContent("To begin animating {0}, create {1}."); diff --git a/Editor/Mono/Animation/AnimationWindow/CurveEditor.cs b/Editor/Mono/Animation/AnimationWindow/CurveEditor.cs index eccff33fca..f93cca8339 100644 --- a/Editor/Mono/Animation/AnimationWindow/CurveEditor.cs +++ b/Editor/Mono/Animation/AnimationWindow/CurveEditor.cs @@ -1326,21 +1326,6 @@ void DragTangents() } } - struct KeyFrameCopy - { - public float time, value, inTangent, outTangent; - public int idx, selectionIdx; - public KeyFrameCopy(int idx, int selectionIdx, Keyframe source) - { - this.idx = idx; - this.selectionIdx = selectionIdx; - time = source.time; - value = source.value; - inTangent = source.inTangent; - outTangent = source.outTangent; - } - } - internal void DeleteSelectedKeys() { string undoLabel; @@ -2882,7 +2867,7 @@ public Vector2 MovePoints() } // Curve dragging. Moving keys has highest priority, therefore we check curve/region dragging AFTER key dragging above - if (settings.allowDraggingCurvesAndRegions && m_DraggingKey == null) + if (evt.shift && settings.allowDraggingCurvesAndRegions && m_DraggingKey == null) { // We use the logic as for moving keys when we drag entire curves or regions: We just // select all keyFrames in a curve or region before dragging and ensure to hide tangents when drawing. diff --git a/Editor/Mono/Animation/AnimationWindow/DopeSheetEditor.cs b/Editor/Mono/Animation/AnimationWindow/DopeSheetEditor.cs index d145872333..4ad6ddec5e 100644 --- a/Editor/Mono/Animation/AnimationWindow/DopeSheetEditor.cs +++ b/Editor/Mono/Animation/AnimationWindow/DopeSheetEditor.cs @@ -394,11 +394,6 @@ private void RectangleToolGUI() m_RectangleTool.OnGUI(); } - private void DrawGrid(Rect position) - { - TimeRuler(position, state.frameRate, false, true, 0.2f); - } - public void DrawMasterDopelineBackground(Rect position) { if (Event.current.type != EventType.Repaint) diff --git a/Editor/Mono/Animation/AnimationWindow/DopeSheetEditorRectangleTool.cs b/Editor/Mono/Animation/AnimationWindow/DopeSheetEditorRectangleTool.cs index 0e3525a3ba..f525046c26 100644 --- a/Editor/Mono/Animation/AnimationWindow/DopeSheetEditorRectangleTool.cs +++ b/Editor/Mono/Animation/AnimationWindow/DopeSheetEditorRectangleTool.cs @@ -3,18 +3,13 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using UnityEngine; -using UnityEditor; using UnityEditorInternal; -using System.Collections; using System.Collections.Generic; -using System.Linq; namespace UnityEditor { internal class DopeSheetEditorRectangleTool : RectangleTool { - const float kDefaultFrameRate = 60f; - const int kScaleLeftWidth = 17; const int kScaleLeftMarginHorizontal = 0; const float kScaleLeftMarginVertical = 4; @@ -382,14 +377,6 @@ private void OnScaleTime(float time) TransformKeys(transform, flipX, false); } - private void OnScaleValue(float val) - { - Matrix4x4 transform; - bool flipY; - if (CalculateScaleValueMatrix(m_Previous.y, val, m_MouseOffset.y, m_Pivot.y, out transform, out flipY)) - TransformKeys(transform, false, flipY); - } - private void OnEndScale() { m_State.EndLiveEdit(); diff --git a/Editor/Mono/Animation/AnimationWindow/RotationCurveInterpolation.cs b/Editor/Mono/Animation/AnimationWindow/RotationCurveInterpolation.cs index 6405421094..ede837fd2c 100644 --- a/Editor/Mono/Animation/AnimationWindow/RotationCurveInterpolation.cs +++ b/Editor/Mono/Animation/AnimationWindow/RotationCurveInterpolation.cs @@ -61,11 +61,6 @@ public static State GetCurveState(AnimationClip clip, EditorCurveBinding[] selec return state; } - public static int GetCurveIndexFromName(string name) - { - return ExtractComponentCharacter(name) - 'x'; - } - public static char ExtractComponentCharacter(string name) { return name[name.Length - 1]; diff --git a/Editor/Mono/Animation/GameObjectRecorder.bindings.cs b/Editor/Mono/Animation/GameObjectRecorder.bindings.cs index 4014083f37..d3afb6b18a 100644 --- a/Editor/Mono/Animation/GameObjectRecorder.bindings.cs +++ b/Editor/Mono/Animation/GameObjectRecorder.bindings.cs @@ -11,12 +11,30 @@ namespace UnityEditor.Animations { + public struct CurveFilterOptions + { + public float positionError; + public float rotationError; + public float scaleError; + public float floatError; + public bool keyframeReduction; + } + [NativeHeader("Editor/Src/Animation/EditorCurveBinding.bindings.h")] [NativeHeader("Editor/Src/Animation/GameObjectRecorder.h")] [NativeHeader("Modules/Animation/AnimationClip.h")] [NativeType] public class GameObjectRecorder : Object { + readonly static CurveFilterOptions k_DefaultCurveFilterOptions = new CurveFilterOptions() + { + keyframeReduction = true, + positionError = 0.5f, + rotationError = 0.5f, + scaleError = 0.5f, + floatError = 0.5f + }; + public GameObjectRecorder(GameObject root) { Internal_Create(this, root); @@ -76,11 +94,36 @@ public void SaveToClip(AnimationClip clip, float fps) { if (fps <= Mathf.Epsilon) throw new ArgumentException("FPS can't be 0.0 or less"); - SaveToClipInternal(clip, fps); + + if (!isRecording) + throw new InvalidOperationException("Cannot save to clip as there is nothing to save. The method TakeSnapshot() has not been called."); + + SaveToClipInternal(clip, fps, k_DefaultCurveFilterOptions); + + AnimationUtility.onCurveWasModified?.Invoke(clip, new EditorCurveBinding(), AnimationUtility.CurveModifiedType.ClipModified); + } + + public void SaveToClip(AnimationClip clip, float fps, CurveFilterOptions filterOptions) + { + if (fps <= Mathf.Epsilon) + throw new ArgumentException("FPS can't be 0.0 or less"); + + if (filterOptions.keyframeReduction) + { + if (filterOptions.positionError < 0 || filterOptions.rotationError < 0 || filterOptions.scaleError < 0 || filterOptions.floatError < 0) + throw new ArgumentException("Allowed errors for keyframe reduction cannot be negative."); + } + + if (!isRecording) + throw new InvalidOperationException("Cannot save to clip as there is nothing to save. The method TakeSnapshot() has not been called."); + + SaveToClipInternal(clip, fps, filterOptions); + + AnimationUtility.onCurveWasModified?.Invoke(clip, new EditorCurveBinding(), AnimationUtility.CurveModifiedType.ClipModified); } [NativeMethod("SaveToClip")] - extern void SaveToClipInternal(AnimationClip clip, float fps); + extern void SaveToClipInternal(AnimationClip clip, float fps, CurveFilterOptions filterOptions); extern public void ResetRecording(); diff --git a/Editor/Mono/Animation/TimeArea.cs b/Editor/Mono/Animation/TimeArea.cs index b89d90a947..cec8607005 100644 --- a/Editor/Mono/Animation/TimeArea.cs +++ b/Editor/Mono/Animation/TimeArea.cs @@ -137,11 +137,6 @@ public void TimeRuler(Rect position, float frameRate) TimeRuler(position, frameRate, true, false, 1f, TimeFormat.TimeFrame); } - public void TimeRuler(Rect position, float frameRate, bool labels, bool useEntireHeight, float alpha) - { - TimeRuler(position, frameRate, labels, useEntireHeight, alpha, TimeFormat.TimeFrame); - } - public void TimeRuler(Rect position, float frameRate, bool labels, bool useEntireHeight, float alpha, TimeFormat timeFormat) { diff --git a/Editor/Mono/Annotation/AnnotationUtility.bindings.cs b/Editor/Mono/Annotation/AnnotationUtility.bindings.cs index 6f13765b97..b4a1c686b9 100644 --- a/Editor/Mono/Annotation/AnnotationUtility.bindings.cs +++ b/Editor/Mono/Annotation/AnnotationUtility.bindings.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 System.Runtime.InteropServices; using UnityEngine.Bindings; @@ -53,6 +54,8 @@ internal sealed partial class AnnotationUtility internal extern static bool use3dGizmos { get; set; } [StaticAccessor("GetAnnotationManager()", StaticAccessorType.Dot)] + // Thomas Tu: 2019-06-20. Will be marked as Obsolete. + // We need to deal with code dependency in packages first. internal extern static bool showGrid { get; set; } [StaticAccessor("GetAnnotationManager()", StaticAccessorType.Dot)] diff --git a/Editor/Mono/Annotation/AnnotationWindow.cs b/Editor/Mono/Annotation/AnnotationWindow.cs index bcf901d692..8514315499 100644 --- a/Editor/Mono/Annotation/AnnotationWindow.cs +++ b/Editor/Mono/Annotation/AnnotationWindow.cs @@ -80,7 +80,6 @@ private enum EnabledState GUIContent iconSelectContent = EditorGUIUtility.TrTextContent("", "Select Icon"); GUIContent icon3dGizmoContent = EditorGUIUtility.TrTextContent("3D Icons"); - GUIContent showGridContent = EditorGUIUtility.TrTextContent("Show Grid"); GUIContent showOutlineContent = EditorGUIUtility.TrTextContent("Selection Outline"); GUIContent showWireframeContent = EditorGUIUtility.TrTextContent("Selection Wire"); private bool m_IsGameView; @@ -144,7 +143,7 @@ static public void IconChanged() float GetTopSectionHeight() { - const int numberOfControls = 4; + const int numberOfControls = 3; return EditorGUI.kSingleLineHeight * numberOfControls + EditorGUI.kControlVerticalSpacing * numberOfControls; } @@ -365,9 +364,6 @@ void DrawTopSection(float topSectionHeight) using (new EditorGUI.DisabledScope(m_IsGameView)) { toggleRect = new Rect(margin, curY, labelWidth, rowHeight); - AnnotationUtility.showGrid = GUI.Toggle(toggleRect, AnnotationUtility.showGrid, showGridContent); - - toggleRect.y += rowHeight; AnnotationUtility.showSelectionOutline = GUI.Toggle(toggleRect, AnnotationUtility.showSelectionOutline, showOutlineContent); toggleRect.y += rowHeight; @@ -714,11 +710,6 @@ public AInfo(bool gizmoEnabled, bool iconEnabled, int flags, int classID, string public string m_DisplayText; public int m_Flags; - bool IsBitSet(byte b, int pos) - { - return (b & (1 << pos)) != 0; - } - public bool HasGizmo() { return (m_Flags & (int)Flags.kHasGizmo) > 0; diff --git a/Editor/Mono/AssemblyHelper.cs b/Editor/Mono/AssemblyHelper.cs index 42632b84a2..56651f2bc5 100644 --- a/Editor/Mono/AssemblyHelper.cs +++ b/Editor/Mono/AssemblyHelper.cs @@ -62,7 +62,7 @@ static public string ExtractInternalAssemblyName(string path) } catch { - return ""; // Possible on just deleted FacebookSDK + return ""; } } diff --git a/Editor/Mono/AssemblyInfo/AssemblyInfo.cs b/Editor/Mono/AssemblyInfo/AssemblyInfo.cs index b11657504f..84e07ca1de 100644 --- a/Editor/Mono/AssemblyInfo/AssemblyInfo.cs +++ b/Editor/Mono/AssemblyInfo/AssemblyInfo.cs @@ -27,6 +27,7 @@ [assembly: InternalsVisibleTo("Unity.IntegrationTests.UnityAnalytics")] [assembly: InternalsVisibleTo("Unity.Timeline.Editor")] [assembly: InternalsVisibleTo("Unity.PackageManagerUI.Develop.Editor")] +[assembly: InternalsVisibleTo("Unity.DeviceSimulator.Editor")] [assembly: InternalsVisibleTo("Unity.Timeline.EditorTests")] [assembly: InternalsVisibleTo("UnityEditor.Graphs")] @@ -58,7 +59,6 @@ [assembly: InternalsVisibleTo("UnityEditor.VR")] [assembly: InternalsVisibleTo("Unity.RuntimeTests")] [assembly: InternalsVisibleTo("Unity.RuntimeTests.Framework")] -[assembly: InternalsVisibleTo("UnityEditor.Facebook.Extensions")] [assembly: InternalsVisibleTo("Assembly-CSharp-Editor-firstpass-testable")] [assembly: InternalsVisibleTo("Assembly-CSharp-Editor-testable")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] diff --git a/Editor/Mono/AssetDatabase/AssetDatabase.bindings.cs b/Editor/Mono/AssetDatabase/AssetDatabase.bindings.cs index 66d6ddb979..329831b836 100644 --- a/Editor/Mono/AssetDatabase/AssetDatabase.bindings.cs +++ b/Editor/Mono/AssetDatabase/AssetDatabase.bindings.cs @@ -23,6 +23,7 @@ internal enum ImportPackageOptions { Default = 0, NoGUI = 1 << 0, + ImportDelayed = 1 << 1 } [NativeHeader("Modules/AssetDatabase/Editor/Public/AssetDatabase.h")] @@ -131,7 +132,7 @@ public static void ForceReserializeAssets() //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, interactive ? ImportPackageOptions.Default : ImportPackageOptions.NoGUI); + ImportPackage(packagePath, ImportPackageOptions.ImportDelayed | (interactive ? ImportPackageOptions.Default : ImportPackageOptions.NoGUI)); } internal static bool ImportPackageImmediately(string packagePath) @@ -140,3 +141,27 @@ internal static bool ImportPackageImmediately(string packagePath) } } } + +namespace UnityEditor.Experimental +{ + public partial class AssetDatabaseExperimental + { + [FreeFunction("AssetDatabase::ClearImporterOverride")] + extern public static void ClearImporterOverride(string path); + + public static void SetImporterOverride(string path) + where T : Experimental.AssetImporters.ScriptedImporter + { + SetImporterOverrideInternal(path, typeof(T)); + } + + [FreeFunction("AssetDatabase::SetImporterOverride")] + extern internal static void SetImporterOverrideInternal(string path, System.Type importer); + + [FreeFunction("AssetDatabase::GetImporterOverride")] + extern public static System.Type GetImporterOverride(string path); + + [FreeFunction("AssetDatabase::GetAvailableImporterTypes")] + extern public static Type[] GetAvailableImporterTypes(string path); + } +} diff --git a/Editor/Mono/AssetPipeline/AssemblyDefinitionImporter.cs b/Editor/Mono/AssetPipeline/AssemblyDefinitionImporter.cs index 850f67d5e6..549b1b9849 100644 --- a/Editor/Mono/AssetPipeline/AssemblyDefinitionImporter.cs +++ b/Editor/Mono/AssetPipeline/AssemblyDefinitionImporter.cs @@ -7,6 +7,7 @@ namespace UnityEditorInternal { + [ExcludeFromPreset] public sealed partial class AssemblyDefinitionImporter : AssetImporter { } diff --git a/Editor/Mono/AssetPipeline/AssemblyDefinitionReferenceImporter.cs b/Editor/Mono/AssetPipeline/AssemblyDefinitionReferenceImporter.cs index f39a634172..3ec57b70e6 100644 --- a/Editor/Mono/AssetPipeline/AssemblyDefinitionReferenceImporter.cs +++ b/Editor/Mono/AssetPipeline/AssemblyDefinitionReferenceImporter.cs @@ -7,6 +7,7 @@ namespace UnityEditorInternal { + [ExcludeFromPreset] public sealed partial class AssemblyDefinitionReferenceImporter : AssetImporter { } diff --git a/Editor/Mono/AssetPipeline/AssetImporter.bindings.cs b/Editor/Mono/AssetPipeline/AssetImporter.bindings.cs index 2377a3fa56..3c1e6b5f00 100644 --- a/Editor/Mono/AssetPipeline/AssetImporter.bindings.cs +++ b/Editor/Mono/AssetPipeline/AssetImporter.bindings.cs @@ -139,7 +139,7 @@ public Dictionary GetExternalObjectMap() } [FreeFunction("AssetImporterBindings::RegisterImporter")] - extern internal static void RegisterImporter(Type importer, int importerVersion, int queuePos, string fileExt, bool supportsImportDependencyHinting); + extern internal static void RegisterImporter(Type importer, int importerVersion, int queuePos, string fileExt, bool supportsImportDependencyHinting, bool autoSelect); [FreeFunction("AssetImporterBindings::SupportsRemappedAssetType", HasExplicitThis = true, IsThreadSafe = true)] public extern bool SupportsRemappedAssetType(Type type); diff --git a/Editor/Mono/AssetPipeline/TextureImporter.bindings.cs b/Editor/Mono/AssetPipeline/TextureImporter.bindings.cs index af16d1efbc..89f7e58e77 100644 --- a/Editor/Mono/AssetPipeline/TextureImporter.bindings.cs +++ b/Editor/Mono/AssetPipeline/TextureImporter.bindings.cs @@ -7,7 +7,6 @@ using System.ComponentModel; using UnityEditor.Build; using UnityEditor.Experimental.AssetImporters; -using UnityEditor.Experimental.U2D; using UnityEngine; using UnityEngine.Bindings; using UnityEngine.Scripting; diff --git a/Editor/Mono/AssetPostprocessor.cs b/Editor/Mono/AssetPostprocessor.cs index 7d84ec8afe..7cf90e2ea0 100644 --- a/Editor/Mono/AssetPostprocessor.cs +++ b/Editor/Mono/AssetPostprocessor.cs @@ -14,6 +14,8 @@ using UnityEditor.AssetImporters; using Object = UnityEngine.Object; using UnityEditor.Experimental.AssetImporters; +using UnityEditorInternal; +using Unity.CodeEditor; namespace UnityEditor { @@ -87,8 +89,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 - CodeEditorProjectSync.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(); } @@ -101,6 +111,67 @@ static void PreprocessAssembly(string pathName) } } + //This is undocumented, and a "safeguard" for when visualstudio gets a new release that is incompatible with ours, so that users can postprocess our csproj to fix it. + //(or just completely replace them). Hopefully we'll never need this. + static internal void CallOnGeneratedCSProjectFiles() + { + object[] args = {}; + foreach (var method in AllPostProcessorMethodsNamed("OnGeneratedCSProjectFiles")) + { + InvokeMethod(method, args); + } + } + + //This callback is used by C# code editors to modify the .sln file. + static internal string CallOnGeneratedSlnSolution(string path, string content) + { + foreach (var method in AllPostProcessorMethodsNamed("OnGeneratedSlnSolution")) + { + object[] args = { path, content }; + object returnValue = InvokeMethod(method, args); + + if (method.ReturnType == typeof(string)) + content = (string)returnValue; + } + + return content; + } + + // This callback is used by C# code editors to modify the .csproj files. + static internal string CallOnGeneratedCSProject(string path, string content) + { + foreach (var method in AllPostProcessorMethodsNamed("OnGeneratedCSProject")) + { + object[] args = { path, content }; + object returnValue = InvokeMethod(method, args); + + if (method.ReturnType == typeof(string)) + content = (string)returnValue; + } + + return content; + } + + //This callback is used by UnityVS to take over project generation from unity + static internal bool OnPreGeneratingCSProjectFiles() + { + object[] args = {}; + bool result = false; + foreach (var method in AllPostProcessorMethodsNamed("OnPreGeneratingCSProjectFiles")) + { + object returnValue = InvokeMethod(method, args); + + if (method.ReturnType == typeof(bool)) + result = result | (bool)returnValue; + } + return result; + } + + private static IEnumerable AllPostProcessorMethodsNamed(string callbackName) + { + return GetCachedAssetPostprocessorClasses().Select(assetPostprocessorClass => assetPostprocessorClass.GetMethod(callbackName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)).Where(method => method != null); + } + internal class CompareAssetImportPriority : IComparer { int IComparer.Compare(System.Object xo, System.Object yo) @@ -136,6 +207,7 @@ internal class PostprocessStack static string m_MeshProcessorsHashString = null; static string m_TextureProcessorsHashString = null; static string m_AudioProcessorsHashString = null; + static string m_SpeedTreeProcessorsHashString = null; static Type[] GetCachedAssetPostprocessorClasses() { @@ -534,6 +606,42 @@ static void PostprocessAssetbundleNameChanged(string assetPAth, string prevoiusA } } + [RequiredByNativeCode] + static string GetSpeedTreeProcessorsHashString() + { + if (m_SpeedTreeProcessorsHashString != null) + return m_SpeedTreeProcessorsHashString; + + var versionsByType = new SortedList(); + + foreach (var assetPostprocessorClass in GetCachedAssetPostprocessorClasses()) + { + try + { + var inst = Activator.CreateInstance(assetPostprocessorClass) as AssetPostprocessor; + var type = inst.GetType(); + bool hasPreProcessMethod = type.GetMethod("OnPreprocessSpeedTree", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) != null; + bool hasPostProcessMethod = type.GetMethod("OnPostprocessSpeedTree", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) != null; + uint version = inst.GetVersion(); + if (version != 0 && (hasPreProcessMethod || hasPostProcessMethod)) + { + versionsByType.Add(type.FullName, version); + } + } + catch (MissingMethodException) + { + LogPostProcessorMissingDefaultConstructor(assetPostprocessorClass); + } + catch (Exception e) + { + Debug.LogException(e); + } + } + + m_SpeedTreeProcessorsHashString = BuildHashString(versionsByType); + return m_SpeedTreeProcessorsHashString; + } + static object InvokeMethod(MethodInfo method, object[] args) { bool profile = Profiler.enabled; diff --git a/Editor/Mono/AssetStore/AssetStoreAssetSelection.cs b/Editor/Mono/AssetStore/AssetStoreAssetSelection.cs index 2aed8725b2..64e139622d 100644 --- a/Editor/Mono/AssetStore/AssetStoreAssetSelection.cs +++ b/Editor/Mono/AssetStore/AssetStoreAssetSelection.cs @@ -46,7 +46,7 @@ public static void AddAsset(AssetStoreAsset searchResult, Texture2D placeholderP // Request the asset bundle data from the url and register a callback AsyncHTTPClient client = new AsyncHTTPClient(searchResult.dynamicPreviewURL); - client.doneCallback = delegate(AsyncHTTPClient c) { + client.doneCallback = delegate(IAsyncHTTPClient c) { if (!client.IsSuccess()) { System.Console.WriteLine("Error downloading dynamic preview: " + client.text); @@ -161,7 +161,7 @@ internal static void AddAssetInternal(AssetStoreAsset searchResult) static void DownloadStaticPreview(AssetStoreAsset searchResult) { AsyncHTTPClient client = new AsyncHTTPClient(searchResult.staticPreviewURL); - client.doneCallback = delegate(AsyncHTTPClient c) { + client.doneCallback = delegate(IAsyncHTTPClient c) { if (!client.IsSuccess()) { System.Console.WriteLine("Error downloading static preview: " + client.text); diff --git a/Editor/Mono/AssetStore/AssetStoreClient.cs b/Editor/Mono/AssetStore/AssetStoreClient.cs index bad9658651..6667ea7388 100644 --- a/Editor/Mono/AssetStore/AssetStoreClient.cs +++ b/Editor/Mono/AssetStore/AssetStoreClient.cs @@ -28,7 +28,7 @@ namespace UnityEditor */ class AssetStoreResponse { - internal AsyncHTTPClient job; + internal IAsyncHTTPClient job; public Dictionary dict; public bool ok; public bool failed { get { return !ok; } } @@ -568,7 +568,7 @@ internal static void LoginWithRememberedSession(DoneLoginCallback callback) // Helper function for login callbacks static AsyncHTTPClient.DoneCallback WrapLoginCallback(DoneLoginCallback callback) { - return delegate(AsyncHTTPClient job) { + return delegate(IAsyncHTTPClient job) { // We're logging in string msg = job.text; if (!job.IsSuccess()) @@ -629,20 +629,6 @@ static AsyncHTTPClient CreateJSONRequestPost(string url, Dictionary m_CachedAssetStoreImages; - const double kQueryDelay = 0.2; const int kMaxConcurrentDownloads = 15; const int kMaxConvertionsPerTick = 1; int m_MaxCachedAssetStoreImages = 10; @@ -195,7 +194,7 @@ private static AsyncHTTPClient SetupTextureDownload(CachedAssetStoreImage cached AsyncHTTPClient client = new AsyncHTTPClient(url); cached.client = client; client.tag = tag; - client.doneCallback = delegate(AsyncHTTPClient c) { + client.doneCallback = delegate(IAsyncHTTPClient c) { // Debug.Log("Got image " + EditorApplication.timeSinceStartup.ToString()); cached.client = null; if (!client.IsSuccess()) diff --git a/Editor/Mono/AssetStoreUtils.bindings.cs b/Editor/Mono/AssetStoreUtils.bindings.cs index e51920cc14..a2f2889360 100644 --- a/Editor/Mono/AssetStoreUtils.bindings.cs +++ b/Editor/Mono/AssetStoreUtils.bindings.cs @@ -17,6 +17,7 @@ internal class AssetStoreUtils extern public static void Download(string id, string url, string[] destination, string key, string jsonData, bool resumeOK, DownloadDoneCallback doneCallback = null); extern public static string CheckDownload(string id, string url, string[] destination, string key); + extern public static bool AbortDownload(string id, string[] destination); extern public static void RegisterDownloadDelegate([NotNull] ScriptableObject d); extern public static void UnRegisterDownloadDelegate([NotNull] ScriptableObject d); extern public static string GetLoaderPath(); diff --git a/Editor/Mono/AsyncHTTPClient.bindings.cs b/Editor/Mono/AsyncHTTPClient.bindings.cs index 896fb806a7..ac2ee8028f 100644 --- a/Editor/Mono/AsyncHTTPClient.bindings.cs +++ b/Editor/Mono/AsyncHTTPClient.bindings.cs @@ -20,6 +20,8 @@ internal partial class AsyncHTTPClient private static extern Texture2D GetTextureByHandle(IntPtr handle); + private static extern string[] GetHeadersByHandle(IntPtr handle); + public static extern void AbortByTag(string tag); private static extern void AbortByHandle(IntPtr handle); diff --git a/Editor/Mono/AsyncHTTPClient.cs b/Editor/Mono/AsyncHTTPClient.cs index 573ac6cccd..e117890755 100644 --- a/Editor/Mono/AsyncHTTPClient.cs +++ b/Editor/Mono/AsyncHTTPClient.cs @@ -13,11 +13,37 @@ namespace UnityEditor { + internal interface IAsyncHTTPClient + { + string text { get; } + byte[] bytes { get; } + Texture2D texture { get; } + AsyncHTTPClient.State state { get; } + int responseCode { get; } + string tag { get; set; } + Dictionary header { get; set; } + + Dictionary responseHeader { get; } + + string postData { set; } + Dictionary postDictionary { set; } + + AsyncHTTPClient.DoneCallback doneCallback { get; set; } + + string url { get; } + + void Abort(); + bool IsAborted(); + bool IsDone(); + bool IsSuccess(); + void Begin(); + } + /* * A HTTP job for performing HTTP requests in a thread * This class is primarily used by the Server class. */ - internal partial class AsyncHTTPClient + internal partial class AsyncHTTPClient : IAsyncHTTPClient { internal enum State { @@ -33,11 +59,11 @@ internal enum State TIMEOUT } private IntPtr m_Handle; - public delegate void DoneCallback(AsyncHTTPClient client); + public delegate void DoneCallback(IAsyncHTTPClient client); public delegate void StatusCallback(State status, int bytesDone, int bytesTotal); public StatusCallback statusCallback; - public DoneCallback doneCallback; + public DoneCallback doneCallback { get; set; } string m_ToUrl; string m_FromData; @@ -73,11 +99,30 @@ public Texture2D texture return GetTextureByHandle(m_Handle); } } + public State state { get; private set; } public int responseCode { get; private set; } public string tag { get; set; } - public Dictionary header; + public Dictionary responseHeader + { + get + { + string[] headerFlattened = GetHeadersByHandle(m_Handle); + Dictionary ret = new Dictionary(); + foreach (var curr in headerFlattened) + { + string[] line = curr.Split(new string[] { ": " }, StringSplitOptions.None); + if (line.Length > 1) + ret.Add(line[0], string.Concat(line.Skip(1).ToArray())); + else + ret.Add(curr, ""); + } + return ret; + } + } + + public Dictionary header { get; set; } /* GET request * diff --git a/Editor/Mono/Audio/Mixer/GUI/AudioMixerChannelStripView.cs b/Editor/Mono/Audio/Mixer/GUI/AudioMixerChannelStripView.cs index ddf24fc77f..d9a074e5ca 100644 --- a/Editor/Mono/Audio/Mixer/GUI/AudioMixerChannelStripView.cs +++ b/Editor/Mono/Audio/Mixer/GUI/AudioMixerChannelStripView.cs @@ -1133,7 +1133,7 @@ class ChannelStripParams public void Init(AudioMixerController controller, Rect channelStripRect, int maxNumEffects) { - numChannels = controller.GetGroupVUInfo(group.groupID, false, ref vuinfo_level, ref vuinfo_peak); + numChannels = controller.GetGroupVUInfo(group.groupID, false, vuinfo_level, vuinfo_peak); //numChannels = 8; // debugging maxEffects = maxNumEffects; diff --git a/Editor/Mono/Audio/Mixer/GUI/AudioMixerEffectView.cs b/Editor/Mono/Audio/Mixer/GUI/AudioMixerEffectView.cs index 89f6e54a4d..34bdaff370 100644 --- a/Editor/Mono/Audio/Mixer/GUI/AudioMixerEffectView.cs +++ b/Editor/Mono/Audio/Mixer/GUI/AudioMixerEffectView.cs @@ -244,7 +244,7 @@ public void DoEffectGUI(int effectIndex, AudioMixerGroupController group, List additionalBlacklist, BuildTargetGroup buildTargetGroup, ManagedStrippingLevel managedStrippingLevel, bool stripEngineCode, string editorToLinkerDataPath) + static IEnumerable SanitizeLinkXmlFilePaths(List linkXmlFilePaths, UnityLinkerRunInformation runInformation) { - if (!Directory.Exists(outputFolder)) - Directory.CreateDirectory(outputFolder); + foreach (var linkXmlFilePath in linkXmlFilePaths) + { + // Generated link xml files that would have been empty will be nulled out. Need to filter these out before running the linker + if (string.IsNullOrEmpty(linkXmlFilePath)) + continue; - additionalBlacklist = additionalBlacklist.Select(s => Path.IsPathRooted(s) ? s : Path.Combine(workingDirectory, s)).Where(File.Exists); + var absolutePath = linkXmlFilePath; + if (!Path.IsPathRooted(linkXmlFilePath)) + absolutePath = Path.Combine(runInformation.managedAssemblyFolderPath, linkXmlFilePath); - var userBlackLists = GetUserBlacklistFiles(); + if (File.Exists(absolutePath)) + yield return absolutePath; + } + } - foreach (var ub in userBlackLists) - Console.WriteLine("UserBlackList: " + ub); + private static bool StripAssembliesTo(string outputFolder, out string output, out string error, IEnumerable linkXmlFiles, UnityLinkerRunInformation runInformation) + { + if (!Directory.Exists(outputFolder)) + Directory.CreateDirectory(outputFolder); - additionalBlacklist = additionalBlacklist.Concat(userBlackLists); + var assemblies = runInformation.AssembliesToProcess(); var args = new List { @@ -75,17 +86,16 @@ private static bool StripAssembliesTo(string[] assemblies, string[] searchDirs, if (!UseUnityLinkerEngineModuleStripping) { - args.Add($"-x={CommandLineFormatter.PrepareFileName(GetModuleWhitelist("Core", platformProvider.moduleStrippingInformationFolder))}"); + args.Add($"-x={CommandLineFormatter.PrepareFileName(GetModuleWhitelist("Core", runInformation.platformProvider.moduleStrippingInformationFolder))}"); } - args.AddRange(additionalBlacklist.Select(path => $"-x={CommandLineFormatter.PrepareFileName(path)}")); - - args.AddRange(searchDirs.Select(d => $"-d={CommandLineFormatter.PrepareFileName(d)}")); + args.AddRange(linkXmlFiles.Select(path => $"-x={CommandLineFormatter.PrepareFileName(path)}")); + args.AddRange(runInformation.SearchDirectories.Select(d => $"-d={CommandLineFormatter.PrepareFileName(d)}")); args.AddRange(assemblies.Select(assembly => $"--include-unity-root-assembly={CommandLineFormatter.PrepareFileName(Path.GetFullPath(assembly))}")); - args.Add($"--dotnetruntime={GetRuntimeArgumentValueForLinker(buildTargetGroup)}"); - args.Add($"--dotnetprofile={GetProfileArgumentValueForLinker(buildTargetGroup)}"); + args.Add($"--dotnetruntime={runInformation.argumentProvider.Runtime}"); + args.Add($"--dotnetprofile={runInformation.argumentProvider.Profile}"); args.Add("--use-editor-options"); - args.Add($"--include-directory={CommandLineFormatter.PrepareFileName(workingDirectory)}"); + args.Add($"--include-directory={CommandLineFormatter.PrepareFileName(runInformation.managedAssemblyFolderPath)}"); if (EditorUserBuildSettings.allowDebugging) args.Add("--editor-settings-flag=AllowDebugging"); @@ -93,33 +103,32 @@ private static bool StripAssembliesTo(string[] assemblies, string[] searchDirs, if (EditorUserBuildSettings.development) args.Add("--editor-settings-flag=Development"); - args.Add($"--rule-set={GetRuleSetForStrippingLevel(managedStrippingLevel)}"); - args.Add($"--editor-data-file={CommandLineFormatter.PrepareFileName(editorToLinkerDataPath)}"); + args.Add($"--rule-set={runInformation.argumentProvider.RuleSet}"); + args.Add($"--editor-data-file={CommandLineFormatter.PrepareFileName(runInformation.EditorToLinkerDataPath)}"); - var compilerPlatform = ""; - var compilerArchitecture = ""; - Il2CppNativeCodeBuilder il2cppNativeCodeBuilder = platformProvider.CreateIl2CppNativeCodeBuilder(); - if (il2cppNativeCodeBuilder != null) + if (runInformation.platformProvider.AllowOutputToBeMadePlatformDependent) { - compilerPlatform = il2cppNativeCodeBuilder.CompilerPlatform; - compilerArchitecture = il2cppNativeCodeBuilder.CompilerArchitecture; + var platform = runInformation.platformProvider.Platform; + if (string.IsNullOrEmpty(platform)) + throw new ArgumentException($"Platform is required if AllowOutputToBeMadePlatformDependent is true"); + + args.Add($"--platform={platform}"); } - else + + if (runInformation.platformProvider.AllowOutputToBeMadeArchitectureDependent) { - // When the scripting backend is not IL2CPP, we have to map those strings and use a utility function to figure out proper strings. - GetUnityLinkerPlatformStringsFromBuildTarget(platformProvider.target, out compilerPlatform, out compilerArchitecture); + var architecture = runInformation.platformProvider.Architecture; + if (string.IsNullOrEmpty(architecture)) + throw new ArgumentException($"Architecture is required if AllowOutputToBeMadeArchitectureDependent is true"); + args.Add($"--architecture={architecture}"); } - args.Add($"--platform={compilerPlatform}"); - if (!string.IsNullOrEmpty(compilerArchitecture)) - args.Add($"--architecture={compilerArchitecture}"); - if (!UseUnityLinkerEngineModuleStripping) { args.Add("--disable-engine-module-support"); } - if (stripEngineCode) + if (runInformation.performEngineStripping) { args.Add("--enable-engine-module-stripping"); @@ -135,11 +144,11 @@ private static bool StripAssembliesTo(string[] assemblies, string[] searchDirs, if (UnityEditor.CrashReporting.CrashReportingSettings.enabled) args.Add("--engine-stripping-flag=EnableCrashReporting"); - if (UnityEditorInternal.VR.VRModule.ShouldInjectVRDependenciesForBuildTarget(platformProvider.target)) + if (UnityEditorInternal.VR.VRModule.ShouldInjectVRDependenciesForBuildTarget(runInformation.target)) args.Add("--engine-stripping-flag=EnableVR"); } - var modulesAssetPath = Path.Combine(platformProvider.moduleStrippingInformationFolder, "../modules.asset"); + var modulesAssetPath = runInformation.ModulesAssetFilePath; if (File.Exists(modulesAssetPath)) args.Add($"--engine-modules-asset-file={CommandLineFormatter.PrepareFileName(modulesAssetPath)}"); @@ -151,68 +160,7 @@ private static bool StripAssembliesTo(string[] assemblies, string[] searchDirs, if (!string.IsNullOrEmpty(additionalArgs)) args.Add(additionalArgs.Trim('\'')); - return RunAssemblyLinker(args, out output, out error, linkerPath, workingDirectory); - } - - private static string GetRuleSetForStrippingLevel(ManagedStrippingLevel managedStrippingLevel) - { - switch (managedStrippingLevel) - { - case ManagedStrippingLevel.Low: - return "Conservative"; - case ManagedStrippingLevel.Medium: - return "Aggressive"; - case ManagedStrippingLevel.High: - return "Experimental"; - } - - throw new ArgumentException($"Unhandled {nameof(ManagedStrippingLevel)} value of {managedStrippingLevel}"); - } - - private static void GetUnityLinkerPlatformStringsFromBuildTarget(BuildTarget target, out string platform, out string architecture) - { - switch (target) - { - case BuildTarget.StandaloneWindows64: - platform = "WindowsDesktop"; - architecture = "x64"; - break; - case BuildTarget.StandaloneWindows: - platform = "WindowsDesktop"; - architecture = "x86"; - break; - case BuildTarget.Android: - // Do not supply architecture for Android. - // The build pipeline bundles multiple architectures for Android. - // Can't narrow down to a specific architecture at strip time, we work around - // that fact in the UnityLinker. - platform = "Android"; - architecture = ""; - break; - case BuildTarget.StandaloneLinux64: - platform = "Linux"; - architecture = "x64"; - break; - case BuildTarget.StandaloneOSX: - platform = "MacOSX"; - architecture = "x64"; - break; - case BuildTarget.WSAPlayer: - platform = "WinRT"; - // Could be multiple values. We don't have use of this information yet so don't bother with trying to figure out what it should be - architecture = ""; - break; - case BuildTarget.iOS: - platform = "iOS"; - architecture = "ARM64"; - break; - case BuildTarget.tvOS: - platform = "tvOS"; - architecture = "ARM64"; - break; - default: - throw new ArgumentException($"Mapping to UnityLinker platform not implemented for {nameof(BuildTarget)} `{target}`"); - } + return RunAssemblyLinker(args, out output, out error, UnityLinkerPath, runInformation.managedAssemblyFolderPath); } private static bool RunAssemblyLinker(IEnumerable args, out string @out, out string err, string linkerPath, string workingDirectory) @@ -227,23 +175,11 @@ private static bool RunAssemblyLinker(IEnumerable args, out string @out, return true; } - private static List GetUserAssemblies(RuntimeClassRegistry rcr, string managedDir) + internal static void StripAssemblies(string managedAssemblyFolderPath, BaseUnityLinkerPlatformProvider unityLinkerPlatformProvider, IIl2CppPlatformProvider il2cppPlatformProvider, + RuntimeClassRegistry rcr, ManagedStrippingLevel managedStrippingLevel) { - return rcr.GetUserAssemblies().Where(s => rcr.IsDLLUsed(s)).Select(s => Path.Combine(managedDir, s)).ToList(); - } - - internal static void StripAssemblies(string managedAssemblyFolderPath, IIl2CppPlatformProvider platformProvider, RuntimeClassRegistry rcr, ManagedStrippingLevel managedStrippingLevel) - { - var assemblies = GetUserAssemblies(rcr, managedAssemblyFolderPath); - assemblies.AddRange(Directory.GetFiles(managedAssemblyFolderPath, "I18N*.dll", SearchOption.TopDirectoryOnly)); - var assembliesToStrip = assemblies.ToArray(); - - var searchDirs = new[] - { - managedAssemblyFolderPath - }; - - RunAssemblyStripper(assemblies, managedAssemblyFolderPath, assembliesToStrip, searchDirs, UnityLinkerPath, platformProvider, rcr, managedStrippingLevel); + var runInformation = new UnityLinkerRunInformation(managedAssemblyFolderPath, unityLinkerPlatformProvider, il2cppPlatformProvider.target, rcr, managedStrippingLevel, il2cppPlatformProvider); + RunAssemblyStripper(runInformation); } internal static void GenerateInternalCallSummaryFile(string icallSummaryPath, string managedAssemblyFolderPath, string strippedDLLPath) @@ -258,12 +194,45 @@ internal static void GenerateInternalCallSummaryFile(string icallSummaryPath, st Runner.RunManagedProgram(exe, args); } + static List ProcessBuildPipelineGenerateAdditionalLinkXmlFiles(UnityLinkerRunInformation runInformation) + { + var results = new List(); + var processors = BuildPipelineInterfaces.processors.unityLinkerProcessors; + if (processors == null) + return results; + + foreach (var processor in processors) + results.Add(processor.GenerateAdditionalLinkXmlFile(runInformation.BuildReport, runInformation.pipelineData)); + + return results; + } + + static void ProcessBuildPipelineOnBeforeRun(UnityLinkerRunInformation runInformation) + { + var processors = BuildPipelineInterfaces.processors.unityLinkerProcessors; + if (processors == null) + return; + + foreach (var processor in processors) + processor.OnBeforeRun(runInformation.BuildReport, runInformation.pipelineData); + } + + static void ProcessBuildPipelineOnAfterRun(UnityLinkerRunInformation runInformation) + { + var processors = BuildPipelineInterfaces.processors.unityLinkerProcessors; + if (processors == null) + return; + + foreach (var processor in processors) + processor.OnAfterRun(runInformation.BuildReport, runInformation.pipelineData); + } + internal static IEnumerable GetUserBlacklistFiles() { return Directory.GetFiles("Assets", "link.xml", SearchOption.AllDirectories).Select(s => Path.Combine(Directory.GetCurrentDirectory(), s)); } - private static bool AddWhiteListsForModules(IEnumerable nativeModules, ref IEnumerable blacklists, string moduleStrippingInformationFolder) + private static bool AddWhiteListsForModules(IEnumerable nativeModules, List blacklists, string moduleStrippingInformationFolder) { bool result = false; foreach (var module in nativeModules) @@ -274,7 +243,7 @@ private static bool AddWhiteListsForModules(IEnumerable nativeModules, r { if (!blacklists.Contains(moduleWhitelist)) { - blacklists = blacklists.Concat(new[] { moduleWhitelist }); + blacklists.Add(moduleWhitelist); result = true; } } @@ -282,71 +251,49 @@ private static bool AddWhiteListsForModules(IEnumerable nativeModules, r return result; } - private static string GetRuntimeArgumentValueForLinker(BuildTargetGroup buildTargetGroup) - { - var backend = PlayerSettings.GetScriptingBackend(buildTargetGroup); - switch (backend) - { - case ScriptingImplementation.IL2CPP: - return "il2cpp"; - case ScriptingImplementation.Mono2x: - return "mono"; - default: - throw new NotImplementedException($"Don't know the backend value to pass to UnityLinker for {backend}"); - } - } - - private static string GetProfileArgumentValueForLinker(BuildTargetGroup buildTargetGroup) - { - return IL2CPPUtils.ApiCompatibilityLevelToDotNetProfileArgument(PlayerSettings.GetApiCompatibilityLevel(buildTargetGroup)); - } - - private static void RunAssemblyStripper(IEnumerable assemblies, string managedAssemblyFolderPath, string[] assembliesToStrip, string[] searchDirs, string monoLinkerPath, IIl2CppPlatformProvider platformProvider, RuntimeClassRegistry rcr, ManagedStrippingLevel managedStrippingLevel) + private static void RunAssemblyStripper(UnityLinkerRunInformation runInformation) { string output; string error; - var buildTargetGroup = BuildPipeline.GetBuildTargetGroup(platformProvider.target); - bool isMono = PlayerSettings.GetScriptingBackend(buildTargetGroup) == ScriptingImplementation.Mono2x; - bool engineStrippingSupported = platformProvider.supportsEngineStripping && !isMono; - bool performEngineStripping = rcr != null && PlayerSettings.stripEngineCode && engineStrippingSupported; - IEnumerable blacklists = Il2CppBlacklistPaths; + var rcr = runInformation.rcr; + var managedAssemblyFolderPath = runInformation.managedAssemblyFolderPath; + var linkXmlFiles = new List(); + linkXmlFiles.AddRange(Il2CppBlacklistPaths); if (rcr != null) { - blacklists = blacklists.Concat(new[] - { - WriteMethodsToPreserveBlackList(rcr, platformProvider.target), - MonoAssemblyStripping.GenerateLinkXmlToPreserveDerivedTypes(managedAssemblyFolderPath, rcr), - WriteTypesInScenesBlacklist(managedAssemblyFolderPath, rcr) - }); + linkXmlFiles.Add(WriteMethodsToPreserveBlackList(rcr, runInformation.target)); + linkXmlFiles.Add(MonoAssemblyStripping.GenerateLinkXmlToPreserveDerivedTypes(managedAssemblyFolderPath, rcr)); + linkXmlFiles.Add(WriteTypesInScenesBlacklist(managedAssemblyFolderPath, rcr)); } - if (isMono) + linkXmlFiles.AddRange(ProcessBuildPipelineGenerateAdditionalLinkXmlFiles(runInformation)); + linkXmlFiles.AddRange(GetUserBlacklistFiles()); + + if (runInformation.isMonoBackend) { // The old Mono assembly stripper uses per-platform link.xml files if available. Apply these here. - var buildToolsDirectory = BuildPipeline.GetBuildToolsDirectory(platformProvider.target); + var buildToolsDirectory = BuildPipeline.GetBuildToolsDirectory(runInformation.target); if (!string.IsNullOrEmpty(buildToolsDirectory)) { var platformDescriptor = Path.Combine(buildToolsDirectory, "link.xml"); if (File.Exists(platformDescriptor)) - blacklists = blacklists.Concat(new[] {platformDescriptor}); + linkXmlFiles.Add(platformDescriptor); } } - string editorToLinkerDataPath = WriteEditorData(managedAssemblyFolderPath, rcr); + WriteEditorData(runInformation); - if (!performEngineStripping && !UseUnityLinkerEngineModuleStripping) + if (!runInformation.performEngineStripping && !UseUnityLinkerEngineModuleStripping) { // if we don't do stripping, add all modules blacklists. - foreach (var file in Directory.GetFiles(platformProvider.moduleStrippingInformationFolder, "*.xml")) - blacklists = blacklists.Concat(new[] {file}); + linkXmlFiles.AddRange(runInformation.GetModuleBlacklistFiles()); } - // Generated link xml files that would have been empty will be nulled out. Need to filter these out before running the linker - blacklists = blacklists.Where(b => b != null); - var tempStripPath = Path.GetFullPath(Path.Combine(managedAssemblyFolderPath, "tempStrip")); + ProcessBuildPipelineOnBeforeRun(runInformation); + bool addedMoreBlacklists; do { @@ -356,39 +303,31 @@ private static void RunAssemblyStripper(IEnumerable assemblies, string managedAs throw new OperationCanceledException(); if (!StripAssembliesTo( - assembliesToStrip, - searchDirs, tempStripPath, - managedAssemblyFolderPath, out output, out error, - monoLinkerPath, - platformProvider, - blacklists, - buildTargetGroup, - managedStrippingLevel, - performEngineStripping, - editorToLinkerDataPath)) - throw new Exception("Error in stripping assemblies: " + assemblies + ", " + error); - - if (engineStrippingSupported) + SanitizeLinkXmlFilePaths(linkXmlFiles, runInformation), + runInformation)) + throw new Exception("Error in stripping assemblies: " + runInformation.AssembliesToProcess() + ", " + error); + + if (runInformation.engineStrippingSupported) { var icallSummaryPath = Path.Combine(managedAssemblyFolderPath, "ICallSummary.txt"); GenerateInternalCallSummaryFile(icallSummaryPath, managedAssemblyFolderPath, tempStripPath); - if (performEngineStripping && !UseUnityLinkerEngineModuleStripping) + if (runInformation.performEngineStripping && !UseUnityLinkerEngineModuleStripping) { // Find which modules we must include in the build based on Assemblies HashSet nativeClasses; HashSet nativeModules; - CodeStrippingUtils.GenerateDependencies(tempStripPath, icallSummaryPath, rcr, performEngineStripping, out nativeClasses, out nativeModules, platformProvider); + CodeStrippingUtils.GenerateDependencies(tempStripPath, icallSummaryPath, rcr, runInformation.performEngineStripping, out nativeClasses, out nativeModules, runInformation.il2CppPlatformProvider); // Add module-specific blacklists. - addedMoreBlacklists = AddWhiteListsForModules(nativeModules, ref blacklists, platformProvider.moduleStrippingInformationFolder); + addedMoreBlacklists = AddWhiteListsForModules(nativeModules, linkXmlFiles, runInformation.platformProvider.moduleStrippingInformationFolder); } } - if (performEngineStripping && UseUnityLinkerEngineModuleStripping) - UpdateBuildReport(ReadLinkerToEditorData(tempStripPath), platformProvider); + if (runInformation.performEngineStripping && UseUnityLinkerEngineModuleStripping) + UpdateBuildReport(ReadLinkerToEditorData(tempStripPath), runInformation); // If we had to add more whitelists, we need to run AssemblyStripper again with the added whitelists. } @@ -418,11 +357,13 @@ private static void RunAssemblyStripper(IEnumerable assemblies, string managedAs foreach (var dir in Directory.GetDirectories(tempStripPath)) Directory.Move(dir, Path.Combine(managedAssemblyFolderPath, Path.GetFileName(dir))); Directory.Delete(tempStripPath); + + ProcessBuildPipelineOnAfterRun(runInformation); } public static bool UseUnityLinkerEngineModuleStripping { - get { return !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("UNITYLINKER_DISABLE_EMS")); } + get { return string.IsNullOrEmpty(Environment.GetEnvironmentVariable("UNITYLINKER_DISABLE_EMS")); } } private static string WriteTypesInScenesBlacklist(string managedAssemblyDirectory, RuntimeClassRegistry rcr) @@ -454,9 +395,9 @@ private static string WriteTypesInScenesBlacklist(string managedAssemblyDirector return path; } - private static void UpdateBuildReport(LinkerToEditorData dataFromLinker, IIl2CppPlatformProvider platformProvider) + private static void UpdateBuildReport(LinkerToEditorData dataFromLinker, UnityLinkerRunInformation runInformation) { - var strippingInfo = platformProvider == null ? null : StrippingInfo.GetBuildReportData(platformProvider.buildReport); + var strippingInfo = runInformation.BuildReportData; if (strippingInfo == null) return; @@ -500,9 +441,9 @@ internal static LinkerToEditorData ReadLinkerToEditorData(string outputDirectory return data; } - private static string WriteEditorData(string managedAssemblyDirectory, RuntimeClassRegistry rcr) + private static void WriteEditorData(UnityLinkerRunInformation runInformation) { - var items = GetTypesInScenesInformation(managedAssemblyDirectory, rcr); + var items = GetTypesInScenesInformation(runInformation.managedAssemblyFolderPath, runInformation.rcr); List forceIncludeModules; List forceExcludeModules; @@ -516,9 +457,7 @@ private static string WriteEditorData(string managedAssemblyDirectory, RuntimeCl forceExcludeModules = forceExcludeModules.ToArray() }; - var dataPath = Path.Combine(managedAssemblyDirectory, "EditorToUnityLinkerData.json"); - File.WriteAllText(dataPath, JsonUtility.ToJson(editorToLinkerData, true)); - return dataPath; + File.WriteAllText(runInformation.EditorToLinkerDataPath, JsonUtility.ToJson(editorToLinkerData, true)); } static List GetTypesInScenesInformation(string managedAssemblyDirectory, RuntimeClassRegistry rcr) @@ -567,7 +506,9 @@ private static string WriteEditorData(string managedAssemblyDirectory, RuntimeCl items.Add(new EditorToLinkerData.NativeTypeData { name = unityType.name, - module = unityType.module + module = unityType.module, + baseName = unityType.baseClass != null ? unityType.baseClass.name : null, + baseModule = unityType.baseClass != null ? unityType.baseClass.module : null, }); } @@ -634,10 +575,89 @@ static public void StripForMonoBackend(BuildTarget buildTarget, RuntimeClassRegi var stagingAreaData = Paths.Combine("Temp", "StagingArea", "Data"); - var platformProvider = new BaseIl2CppPlatformProvider(buildTarget, Path.Combine(stagingAreaData, "Libraries"), report); + var il2cppPlatformProvider = new MonoBackendIl2CppPlatformProvider(buildTarget, Path.Combine(stagingAreaData, "Libraries"), report); + var platformProvider = new MonoBackendUnityLinkerPlatformProvider(buildTarget); var managedAssemblyFolderPath = Path.GetFullPath(Path.Combine(stagingAreaData, "Managed")); - AssemblyStripper.StripAssemblies(managedAssemblyFolderPath, platformProvider, usedClasses, managedStrippingLevel); + AssemblyStripper.StripAssemblies(managedAssemblyFolderPath, platformProvider, il2cppPlatformProvider, usedClasses, managedStrippingLevel); + } + + class MonoBackendIl2CppPlatformProvider : BaseIl2CppPlatformProvider + { + public MonoBackendIl2CppPlatformProvider(BuildTarget target, string libraryFolder, BuildReport buildReport) + : base(target, libraryFolder, buildReport) + { + } + + public override BaseUnityLinkerPlatformProvider CreateUnityLinkerPlatformProvider() + { + throw new NotSupportedException(); + } + } + + class MonoBackendUnityLinkerPlatformProvider : BaseUnityLinkerPlatformProvider + { + private readonly string m_Platform; + private readonly string m_Architecture; + + public MonoBackendUnityLinkerPlatformProvider(BuildTarget target) : base(target) + { + GetUnityLinkerPlatformStringsFromBuildTarget(target, out m_Platform, out m_Architecture); + } + + public override string Platform => m_Platform; + + public override string Architecture => m_Architecture; + + public override bool AllowOutputToBeMadeArchitectureDependent => !string.IsNullOrEmpty(m_Architecture); + + public override bool supportsEngineStripping => false; + + private static void GetUnityLinkerPlatformStringsFromBuildTarget(BuildTarget target, out string platform, out string architecture) + { + switch (target) + { + case BuildTarget.StandaloneWindows64: + platform = "WindowsDesktop"; + architecture = "x64"; + break; + case BuildTarget.StandaloneWindows: + platform = "WindowsDesktop"; + architecture = "x86"; + break; + case BuildTarget.Android: + // Do not supply architecture for Android. + // The build pipeline bundles multiple architectures for Android. + // Can't narrow down to a specific architecture at strip time, we work around + // that fact in the UnityLinker. + platform = "Android"; + architecture = ""; + break; + case BuildTarget.StandaloneLinux64: + platform = "Linux"; + architecture = "x64"; + break; + case BuildTarget.StandaloneOSX: + platform = "MacOSX"; + architecture = "x64"; + break; + case BuildTarget.WSAPlayer: + platform = "WinRT"; + // Could be multiple values. We don't have use of this information yet so don't bother with trying to figure out what it should be + architecture = ""; + break; + case BuildTarget.iOS: + platform = "iOS"; + architecture = "ARM64"; + break; + case BuildTarget.tvOS: + platform = "tvOS"; + architecture = "ARM64"; + break; + default: + throw new ArgumentException($"Mapping to UnityLinker platform not implemented for {nameof(BuildTarget)} `{target}`"); + } + } } } } diff --git a/Editor/Mono/BuildPipeline/BuildPipelineInterfaces.cs b/Editor/Mono/BuildPipeline/BuildPipelineInterfaces.cs index 084e8cfea4..feb7b737ef 100644 --- a/Editor/Mono/BuildPipeline/BuildPipelineInterfaces.cs +++ b/Editor/Mono/BuildPipeline/BuildPipelineInterfaces.cs @@ -71,6 +71,20 @@ public interface IPreprocessShaders : IOrderedCallback void OnProcessShader(Shader shader, ShaderSnippetData snippet, IList data); } + public interface IUnityLinkerProcessor : IOrderedCallback + { + string GenerateAdditionalLinkXmlFile(BuildReport report, UnityLinker.UnityLinkerBuildPipelineData data); + + void OnBeforeRun(BuildReport report, UnityLinker.UnityLinkerBuildPipelineData data); + + void OnAfterRun(BuildReport report, UnityLinker.UnityLinkerBuildPipelineData data); + } + + public interface IIl2CppProcessor : IOrderedCallback + { + void OnBeforeConvertRun(BuildReport report, Il2Cpp.Il2CppBuildPipelineData data); + } + internal static class BuildPipelineInterfaces { internal class Processors @@ -89,6 +103,9 @@ internal class Processors public List buildTargetProcessors; public List shaderProcessors; public List buildPlayerScriptDLLProcessors; + + public List unityLinkerProcessors; + public List il2cppProcessors; } private static Processors m_Processors; @@ -111,7 +128,9 @@ internal enum BuildCallbacks BuildTargetProcessors = 4, FilterAssembliesProcessors = 8, ShaderProcessors = 16, - BuildPlayerScriptDLLProcessors = 32 + BuildPlayerScriptDLLProcessors = 32, + UnityLinkerProcessors = 64, + I2CppProcessors = 128 } //common comparer for all callback types @@ -185,6 +204,8 @@ internal static void InitializeBuildCallbacks(BuildCallbacks findFlags) bool findFilterProcessors = (findFlags & BuildCallbacks.FilterAssembliesProcessors) == BuildCallbacks.FilterAssembliesProcessors; bool findShaderProcessors = (findFlags & BuildCallbacks.ShaderProcessors) == BuildCallbacks.ShaderProcessors; bool findBuildPlayerScriptDLLsProcessors = (findFlags & BuildCallbacks.BuildPlayerScriptDLLProcessors) == BuildCallbacks.BuildPlayerScriptDLLProcessors; + bool findUnityLinkerProcessors = (findFlags & BuildCallbacks.UnityLinkerProcessors) == BuildCallbacks.UnityLinkerProcessors; + bool findIl2CppProcessors = (findFlags & BuildCallbacks.I2CppProcessors) == BuildCallbacks.I2CppProcessors; var postProcessBuildAttributeParams = new Type[] { typeof(BuildTarget), typeof(string) }; foreach (var t in TypeCache.GetTypesDerivedFrom()) @@ -219,6 +240,16 @@ internal static void InitializeBuildCallbacks(BuildCallbacks findFlags) AddToListIfTypeImplementsInterface(t, ref instance, ref processors.filterBuildAssembliesProcessor); } + if (findUnityLinkerProcessors) + { + AddToListIfTypeImplementsInterface(t, ref instance, ref processors.unityLinkerProcessors); + } + + if (findIl2CppProcessors) + { + AddToListIfTypeImplementsInterface(t, ref instance, ref processors.il2cppProcessors); + } + if (findShaderProcessors) { AddToListIfTypeImplementsInterface(t, ref instance, ref processors.shaderProcessors); @@ -260,6 +291,10 @@ internal static void InitializeBuildCallbacks(BuildCallbacks findFlags) processors.sceneProcessorsWithReport.Sort(CompareICallbackOrder); if (processors.filterBuildAssembliesProcessor != null) processors.filterBuildAssembliesProcessor.Sort(CompareICallbackOrder); + if (processors.unityLinkerProcessors != null) + processors.unityLinkerProcessors.Sort(CompareICallbackOrder); + if (processors.il2cppProcessors != null) + processors.il2cppProcessors.Sort(CompareICallbackOrder); if (processors.shaderProcessors != null) processors.shaderProcessors.Sort(CompareICallbackOrder); if (processors.buildPlayerScriptDLLProcessors != null) @@ -506,6 +541,8 @@ internal static void CleanupBuildCallbacks() processors.buildPostprocessorsWithReport = null; processors.sceneProcessorsWithReport = null; processors.filterBuildAssembliesProcessor = null; + processors.unityLinkerProcessors = null; + processors.il2cppProcessors = null; processors.shaderProcessors = null; processors.buildPlayerScriptDLLProcessors = null; previousFlags = BuildCallbacks.None; diff --git a/Editor/Mono/BuildPipeline/BuildPlatform.cs b/Editor/Mono/BuildPipeline/BuildPlatform.cs index 2ba7145117..7547d96079 100644 --- a/Editor/Mono/BuildPipeline/BuildPlatform.cs +++ b/Editor/Mono/BuildPipeline/BuildPlatform.cs @@ -83,9 +83,6 @@ internal BuildPlatforms() } } - // Facebook is a special case and needs to be added separately - buildPlatformsList.Add(new BuildPlatform(BuildPipeline.GetBuildTargetGroupDisplayName(BuildTargetGroup.Facebook), "BuildSettings.Facebook", BuildTargetGroup.Facebook, BuildTarget.StandaloneWindows64, true)); - foreach (var buildPlatform in buildPlatformsList) { buildPlatform.tooltip = buildPlatform.title.text + " settings"; @@ -130,13 +127,7 @@ public string GetBuildTargetDisplayName(BuildTargetGroup group, BuildTarget targ public string GetModuleDisplayName(BuildTargetGroup buildTargetGroup, BuildTarget buildTarget) { - switch (buildTargetGroup) - { - case BuildTargetGroup.Facebook: - return BuildPipeline.GetBuildTargetGroupDisplayName(buildTargetGroup); - default: - return GetBuildTargetDisplayName(buildTargetGroup, buildTarget); - } + return GetBuildTargetDisplayName(buildTargetGroup, buildTarget); } private int BuildPlatformIndexFromTargetGroup(BuildTargetGroup group) @@ -165,7 +156,7 @@ public List GetValidPlatforms(bool includeMetaPlatforms) { List platforms = new List(); foreach (BuildPlatform bp in buildPlatforms) - if ((bp.targetGroup == BuildTargetGroup.Standalone || BuildPipeline.IsBuildTargetSupported(bp.targetGroup, bp.defaultTarget)) && (!(bp.targetGroup == BuildTargetGroup.Facebook) || includeMetaPlatforms)) + if (bp.targetGroup == BuildTargetGroup.Standalone || BuildPipeline.IsBuildTargetSupported(bp.targetGroup, bp.defaultTarget)) platforms.Add(bp); return platforms; diff --git a/Editor/Mono/BuildPipeline/CodeStrippingUtils.cs b/Editor/Mono/BuildPipeline/CodeStrippingUtils.cs index 390b3404f1..c98599b103 100644 --- a/Editor/Mono/BuildPipeline/CodeStrippingUtils.cs +++ b/Editor/Mono/BuildPipeline/CodeStrippingUtils.cs @@ -147,7 +147,7 @@ public static void GenerateDependencies(string strippedAssemblyDir, string icall } var strippingInfo = platformProvider == null ? null : StrippingInfo.GetBuildReportData(platformProvider.buildReport); - var userAssemblies = GetUserAssemblies(strippedAssemblyDir); + var userAssemblies = GetRequiredAssemblies(strippedAssemblyDir); // [1] Extract native classes from scene and scripts nativeClasses = doStripping ? GenerateNativeClassList(rcr, strippedAssemblyDir, userAssemblies, strippingInfo) : null; @@ -723,7 +723,7 @@ public static string[] UserAssemblies } } - private static string[] GetUserAssemblies(string strippedAssemblyDir) + private static string[] GetRequiredAssemblies(string strippedAssemblyDir) { var arguments = new List(); @@ -733,11 +733,9 @@ private static string[] GetUserAssemblies(string strippedAssemblyDir) arguments.AddRange(files.Select(f => Path.GetFileName(f))); } - // Workaround: if there are no user assemblies (because the project does not contain scripts), add - // UnityEngine, to makes sure we pick up types required by core module. Need to remove this once - // we want to be able to strip core module for ECS only players. - if (arguments.Count == 0) - arguments.Add("UnityEngine.dll"); + // Workaround: Always add UnityEngine to makes sure we pick up types required by core module. Need + // to remove this once we want to be able to strip core module for ECS only players. + arguments.Add("UnityEngine.dll"); return arguments.ToArray(); } diff --git a/Editor/Mono/BuildPipeline/DesktopStandalonePostProcessor.cs b/Editor/Mono/BuildPipeline/DesktopStandalonePostProcessor.cs index 1b7ede217a..41666532b1 100644 --- a/Editor/Mono/BuildPipeline/DesktopStandalonePostProcessor.cs +++ b/Editor/Mono/BuildPipeline/DesktopStandalonePostProcessor.cs @@ -401,18 +401,6 @@ private static uint StringToFourCC(string literal) return result; } - protected static void CopyResolutionDialogBanner(string destinationFolder) - { -#pragma warning disable 618 - var bannerTexture = PlayerSettings.resolutionDialogBanner; - if (bannerTexture != null) - { - var path = Path.Combine(destinationFolder, "ScreenSelector.png"); - IconUtility.SaveTextureToFile(path, bannerTexture, StringToFourCC("PNGf")); - } -#pragma warning restore 618 - } - protected string GetVariationFolder(BuildPostProcessArgs args) => Paths.Combine(args.playerPackage, "Variations", GetVariationName(args)); @@ -425,7 +413,7 @@ protected static void RecordCommonFiles(BuildPostProcessArgs args, string variat // So we find the files in the source Variations directory and mark the corresponding files in the output var path = Path.Combine(variationSourceFolder, "Data/Managed"); foreach (var file in Directory.GetFiles(path, "*.dll") - .Concat(Directory.GetFiles(path, "*.dll.mdb"))) + .Concat(Directory.GetFiles(path, "*.pdb"))) { var filename = Path.GetFileName(file); if (!filename.StartsWith("UnityEngine")) diff --git a/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs b/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs index 3ecc81fbb9..814a6c2978 100644 --- a/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs +++ b/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs @@ -8,8 +8,10 @@ using System.IO; using System.Linq; using UnityEditor; +using UnityEditor.Build; using UnityEditor.Build.Player; using UnityEditor.Build.Reporting; +using UnityEditor.Il2Cpp; using UnityEditor.Scripting; using UnityEditor.Scripting.Compilers; using UnityEditor.Utils; @@ -326,7 +328,7 @@ public void Run() // do try this (which should not be possible from the editor), use Low instead. if (managedStrippingLevel == ManagedStrippingLevel.Disabled) managedStrippingLevel = ManagedStrippingLevel.Low; - AssemblyStripper.StripAssemblies(managedDir, m_PlatformProvider, m_RuntimeClassRegistry, managedStrippingLevel); + AssemblyStripper.StripAssemblies(managedDir, m_PlatformProvider.CreateUnityLinkerPlatformProvider(), m_PlatformProvider, m_RuntimeClassRegistry, managedStrippingLevel); // The IL2CPP editor integration here is responsible to give il2cpp.exe an empty directory to use. FileUtil.CreateOrCleanDirectory(outputDirectory); @@ -334,7 +336,9 @@ public void Run() if (m_ModifyOutputBeforeCompile != null) m_ModifyOutputBeforeCompile(outputDirectory); - ConvertPlayerDlltoCpp(managedDir, outputDirectory, managedDir, m_PlatformProvider.supportsManagedDebugging); + var pipelineData = new Il2CppBuildPipelineData(m_PlatformProvider.target, managedDir); + + ConvertPlayerDlltoCpp(pipelineData, outputDirectory, managedDir, m_PlatformProvider.supportsManagedDebugging); var compiler = m_PlatformProvider.CreateNativeCompiler(); if (compiler != null && m_PlatformProvider.CreateIl2CppNativeCodeBuilder() == null) @@ -400,8 +404,20 @@ public static string GetMapFileParserPath() Application.platform == RuntimePlatform.WindowsEditor ? @"Tools\MapFileParser\MapFileParser.exe" : @"Tools/MapFileParser/MapFileParser")); } - private void ConvertPlayerDlltoCpp(string inputDirectory, string outputDirectory, string workingDirectory, bool platformSupportsManagedDebugging) + static void ProcessBuildPipelineOnBeforeConvertRun(BuildReport report, Il2CppBuildPipelineData data) + { + var processors = BuildPipelineInterfaces.processors.il2cppProcessors; + if (processors == null) + return; + + foreach (var processor in processors) + processor.OnBeforeConvertRun(report, data); + } + + private void ConvertPlayerDlltoCpp(Il2CppBuildPipelineData data, string outputDirectory, string workingDirectory, bool platformSupportsManagedDebugging) { + ProcessBuildPipelineOnBeforeConvertRun(m_PlatformProvider.buildReport, data); + var arguments = new List(); arguments.Add("--convert-to-cpp"); @@ -418,6 +434,9 @@ private void ConvertPlayerDlltoCpp(string inputDirectory, string outputDirectory if (m_PlatformProvider.enableDivideByZeroCheck) arguments.Add("--enable-divide-by-zero-check"); + if (m_PlatformProvider.development && m_PlatformProvider.enableDeepProfilingSupport) + arguments.Add("--enable-deep-profiler"); + if (m_BuildForMonoRuntime) arguments.Add("--mono-runtime"); @@ -448,7 +467,7 @@ private void ConvertPlayerDlltoCpp(string inputDirectory, string outputDirectory if (!string.IsNullOrEmpty(additionalArgs)) arguments.Add(additionalArgs); - arguments.Add($"--directory={CommandLineFormatter.PrepareFileName(Path.GetFullPath(inputDirectory))}"); + arguments.Add($"--directory={CommandLineFormatter.PrepareFileName(Path.GetFullPath(data.inputDirectory))}"); arguments.Add($"--generatedcppdir={CommandLineFormatter.PrepareFileName(Path.GetFullPath(outputDirectory))}"); @@ -557,9 +576,8 @@ internal interface IIl2CppPlatformProvider bool enableStackTraces { get; } bool enableArrayBoundsCheck { get; } bool enableDivideByZeroCheck { get; } + bool enableDeepProfilingSupport { get; } string nativeLibraryFileName { get; } - string moduleStrippingInformationFolder { get; } - bool supportsEngineStripping { get; } bool supportsManagedDebugging { get; } bool supportsUsingIl2cppCore { get; } bool development { get; } @@ -573,9 +591,11 @@ internal interface IIl2CppPlatformProvider INativeCompiler CreateNativeCompiler(); Il2CppNativeCodeBuilder CreateIl2CppNativeCodeBuilder(); CompilerOutputParserBase CreateIl2CppOutputParser(); + + BaseUnityLinkerPlatformProvider CreateUnityLinkerPlatformProvider(); } - internal class BaseIl2CppPlatformProvider : IIl2CppPlatformProvider + internal abstract class BaseIl2CppPlatformProvider : IIl2CppPlatformProvider { public BaseIl2CppPlatformProvider(BuildTarget target, string libraryFolder, BuildReport buildReport) { @@ -609,9 +629,14 @@ public virtual bool enableDivideByZeroCheck get { return false; } } - public virtual bool supportsEngineStripping + public virtual bool enableDeepProfilingSupport { - get { return BuildPipeline.IsFeatureSupported("ENABLE_ENGINE_CODE_STRIPPING", target); } + get + { + if (buildReport != null) + return (buildReport.summary.options & BuildOptions.EnableDeepProfilingSupport) == BuildOptions.EnableDeepProfilingSupport; + return false; + } } public virtual bool supportsManagedDebugging @@ -681,11 +706,6 @@ public virtual string nativeLibraryFileName get { return null; } } - public virtual string moduleStrippingInformationFolder - { - get { return Path.Combine(BuildPipeline.GetPlaybackEngineDirectory(EditorUserBuildSettings.activeBuildTarget, 0), "Whitelists"); } - } - public virtual INativeCompiler CreateNativeCompiler() { return null; @@ -700,5 +720,7 @@ public virtual CompilerOutputParserBase CreateIl2CppOutputParser() { return null; } + + public abstract BaseUnityLinkerPlatformProvider CreateUnityLinkerPlatformProvider(); } } diff --git a/Editor/Mono/BuildPipeline/Il2Cpp/Il2CppBuildPipelineData.cs b/Editor/Mono/BuildPipeline/Il2Cpp/Il2CppBuildPipelineData.cs new file mode 100644 index 0000000000..9b2b9ee0ef --- /dev/null +++ b/Editor/Mono/BuildPipeline/Il2Cpp/Il2CppBuildPipelineData.cs @@ -0,0 +1,21 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +namespace UnityEditor.Il2Cpp +{ + /// + /// Data exposed during IRunIL2CPP callbacks + /// + public sealed class Il2CppBuildPipelineData + { + public readonly BuildTarget target; + public readonly string inputDirectory; + + public Il2CppBuildPipelineData(BuildTarget target, string inputDirectory) + { + this.target = target; + this.inputDirectory = inputDirectory; + } + } +} diff --git a/Editor/Mono/BuildPipeline/PostprocessBuildPlayer.cs b/Editor/Mono/BuildPipeline/PostprocessBuildPlayer.cs index 32b7f7db4c..a3ea6cd179 100644 --- a/Editor/Mono/BuildPipeline/PostprocessBuildPlayer.cs +++ b/Editor/Mono/BuildPipeline/PostprocessBuildPlayer.cs @@ -191,6 +191,14 @@ static public bool SupportsLz4Compression(BuildTargetGroup targetGroup, BuildTar return false; } + static public Compression GetDefaultCompression(BuildTargetGroup targetGroup, BuildTarget target) + { + IBuildPostprocessor postprocessor = ModuleManager.GetBuildPostProcessor(targetGroup, target); + if (postprocessor != null) + return postprocessor.GetDefaultCompression(); + return Compression.None; + } + private class NoTargetsFoundException : Exception { public NoTargetsFoundException() : base() {} diff --git a/Editor/Mono/BuildPipeline/UnityLinker/BaseUnityLinkerPlatformProvider.cs b/Editor/Mono/BuildPipeline/UnityLinker/BaseUnityLinkerPlatformProvider.cs new file mode 100644 index 0000000000..6c049d7b62 --- /dev/null +++ b/Editor/Mono/BuildPipeline/UnityLinker/BaseUnityLinkerPlatformProvider.cs @@ -0,0 +1,46 @@ +// 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.IO; +using UnityEditor; + +namespace UnityEditorInternal +{ + internal abstract class BaseUnityLinkerPlatformProvider + { + protected readonly BuildTarget m_Target; + + public BaseUnityLinkerPlatformProvider(BuildTarget target) + { + this.m_Target = target; + } + + public abstract string Platform { get; } + + public virtual string Architecture => null; + + public virtual bool AllowOutputToBeMadePlatformDependent => true; + + public virtual bool AllowOutputToBeMadeArchitectureDependent + { + get + { + // For now we are not leveraging this capability but I don't want to remove the plumbing to use it + // in case we ever want to take advantage of it + return false; + } + } + + public virtual bool supportsEngineStripping + { + get { return BuildPipeline.IsFeatureSupported("ENABLE_ENGINE_CODE_STRIPPING", m_Target); } + } + + public virtual string moduleStrippingInformationFolder + { + get { return Path.Combine(BuildPipeline.GetPlaybackEngineDirectory(EditorUserBuildSettings.activeBuildTarget, 0), "Whitelists"); } + } + } +} diff --git a/Editor/Mono/BuildPipeline/UnityLinker/UnityLinkerArgumentValueProvider.cs b/Editor/Mono/BuildPipeline/UnityLinker/UnityLinkerArgumentValueProvider.cs new file mode 100644 index 0000000000..2384770694 --- /dev/null +++ b/Editor/Mono/BuildPipeline/UnityLinker/UnityLinkerArgumentValueProvider.cs @@ -0,0 +1,56 @@ +// 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 UnityEditor; + +namespace UnityEditorInternal +{ + class UnityLinkerArgumentValueProvider + { + private readonly UnityLinkerRunInformation m_RunInformation; + + public UnityLinkerArgumentValueProvider(UnityLinkerRunInformation runInformation) + { + this.m_RunInformation = runInformation; + } + + public string Runtime + { + get + { + var backend = PlayerSettings.GetScriptingBackend(m_RunInformation.buildTargetGroup); + switch (backend) + { + case ScriptingImplementation.IL2CPP: + return "il2cpp"; + case ScriptingImplementation.Mono2x: + return "mono"; + default: + throw new NotImplementedException($"Don't know the backend value to pass to UnityLinker for {backend}"); + } + } + } + + public string Profile => IL2CPPUtils.ApiCompatibilityLevelToDotNetProfileArgument(PlayerSettings.GetApiCompatibilityLevel(m_RunInformation.buildTargetGroup)); + + public string RuleSet + { + get + { + switch (m_RunInformation.managedStrippingLevel) + { + case ManagedStrippingLevel.Low: + return "Conservative"; + case ManagedStrippingLevel.Medium: + return "Aggressive"; + case ManagedStrippingLevel.High: + return "Experimental"; + } + + throw new ArgumentException($"Unhandled {nameof(ManagedStrippingLevel)} value of {m_RunInformation.managedStrippingLevel}"); + } + } + } +} diff --git a/Editor/Mono/BuildPipeline/UnityLinker/UnityLinkerBuildPipelineData.cs b/Editor/Mono/BuildPipeline/UnityLinker/UnityLinkerBuildPipelineData.cs new file mode 100644 index 0000000000..d43af2689f --- /dev/null +++ b/Editor/Mono/BuildPipeline/UnityLinker/UnityLinkerBuildPipelineData.cs @@ -0,0 +1,21 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +namespace UnityEditor.UnityLinker +{ + /// + /// Data exposed during IRunUnityLinker callbacks + /// + public sealed class UnityLinkerBuildPipelineData + { + public readonly BuildTarget target; + public readonly string inputDirectory; + + public UnityLinkerBuildPipelineData(BuildTarget target, string inputDirectory) + { + this.target = target; + this.inputDirectory = inputDirectory; + } + } +} diff --git a/Editor/Mono/BuildPipeline/UnityLinker/UnityLinkerRunInformation.cs b/Editor/Mono/BuildPipeline/UnityLinker/UnityLinkerRunInformation.cs new file mode 100644 index 0000000000..64c959ed5b --- /dev/null +++ b/Editor/Mono/BuildPipeline/UnityLinker/UnityLinkerRunInformation.cs @@ -0,0 +1,79 @@ +// 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 UnityEditor; +using UnityEditor.Build.Reporting; +using UnityEditor.UnityLinker; + +namespace UnityEditorInternal +{ + class UnityLinkerRunInformation + { + public readonly string managedAssemblyFolderPath; + public readonly BuildTarget target; + public readonly BuildTargetGroup buildTargetGroup; + public readonly BaseUnityLinkerPlatformProvider platformProvider; + public readonly RuntimeClassRegistry rcr; + public readonly ManagedStrippingLevel managedStrippingLevel; + public readonly UnityLinkerArgumentValueProvider argumentProvider; + public readonly bool engineStrippingSupported; + public readonly bool isMonoBackend; + public readonly bool performEngineStripping; + public readonly IIl2CppPlatformProvider il2CppPlatformProvider; + public readonly UnityLinkerBuildPipelineData pipelineData; + + public UnityLinkerRunInformation(string managedAssemblyFolderPath, + BaseUnityLinkerPlatformProvider platformProvider, BuildTarget buildTarget, + RuntimeClassRegistry rcr, ManagedStrippingLevel managedStrippingLevel, + IIl2CppPlatformProvider il2CppPlatformProvider) + { + this.managedAssemblyFolderPath = managedAssemblyFolderPath; + target = buildTarget; + this.platformProvider = platformProvider; + this.rcr = rcr; + this.managedStrippingLevel = managedStrippingLevel; + this.il2CppPlatformProvider = il2CppPlatformProvider; + pipelineData = new UnityLinkerBuildPipelineData(target, managedAssemblyFolderPath); + + buildTargetGroup = BuildPipeline.GetBuildTargetGroup(buildTarget); + argumentProvider = new UnityLinkerArgumentValueProvider(this); + isMonoBackend = PlayerSettings.GetScriptingBackend(buildTargetGroup) == ScriptingImplementation.Mono2x; + engineStrippingSupported = platformProvider.supportsEngineStripping && !isMonoBackend; + performEngineStripping = rcr != null && PlayerSettings.stripEngineCode && engineStrippingSupported; + } + + public string ModulesAssetFilePath => Path.Combine(platformProvider.moduleStrippingInformationFolder, "../modules.asset"); + + public IEnumerable GetModuleBlacklistFiles() + { + return Directory.GetFiles(platformProvider.moduleStrippingInformationFolder, "*.xml"); + } + + public BuildReport BuildReport => il2CppPlatformProvider == null ? null : il2CppPlatformProvider.buildReport; + + public StrippingInfo BuildReportData => BuildReport == null ? null : StrippingInfo.GetBuildReportData(BuildReport); + + public List GetUserAssemblies() + { + return rcr.GetUserAssemblies().Where(s => rcr.IsDLLUsed(s)).Select(s => Path.Combine(managedAssemblyFolderPath, s)).ToList(); + } + + public List AssembliesToProcess() + { + var userAssemblies = GetUserAssemblies(); + userAssemblies.AddRange(Directory.GetFiles(managedAssemblyFolderPath, "I18N*.dll", SearchOption.TopDirectoryOnly)); + return userAssemblies; + } + + public string EditorToLinkerDataPath => Path.Combine(managedAssemblyFolderPath, "EditorToUnityLinkerData.json"); + + public IEnumerable SearchDirectories + { + get { yield return managedAssemblyFolderPath; } + } + } +} diff --git a/Editor/Mono/BuildPlayerWindow.cs b/Editor/Mono/BuildPlayerWindow.cs index 7d48fd5606..b47eb39a07 100644 --- a/Editor/Mono/BuildPlayerWindow.cs +++ b/Editor/Mono/BuildPlayerWindow.cs @@ -72,7 +72,10 @@ public GUIContent GetDownloadErrorForTarget(BuildTarget target) // string and matching enum values for standalone subtarget dropdowm public GUIContent debugBuild = EditorGUIUtility.TrTextContent("Development Build"); - public GUIContent profileBuild = EditorGUIUtility.TrTextContent("Autoconnect Profiler"); + public GUIContent autoconnectProfiler = EditorGUIUtility.TrTextContent("Autoconnect Profiler", "When the build is started, an open Profiler Window will automatically connect to the Player and start profiling. The \"Build And Run\" option will also automatically open the Profiler Window."); + public GUIContent autoconnectProfilerDisabled = EditorGUIUtility.TrTextContent("Autoconnect Profiler", "Profiling is only enabled in a Development Player."); + public GUIContent buildWithDeepProfiler = EditorGUIUtility.TrTextContent("Deep Profiling Support", "Build Player with Deep Profiling Support. This might affect Player performance."); + public GUIContent buildWithDeepProfilerDisabled = EditorGUIUtility.TrTextContent("Deep Profiling", "Profiling is only enabled in a Development Player."); public GUIContent vrRemoteStremaing = EditorGUIUtility.TrTextContent("VR Remote Streaming"); public GUIContent allowDebugging = EditorGUIUtility.TrTextContent("Script Debugging"); public GUIContent waitForManagedDebugger = EditorGUIUtility.TrTextContent("Wait For Managed Debugger", "Show a dialog where you can attach a managed debugger before any script execution."); @@ -389,13 +392,6 @@ internal static bool IsBuildTargetGroupSupported(BuildTargetGroup targetGroup, B return BuildPipeline.IsBuildTargetSupported(targetGroup, target); } - static void RepairSelectedBuildTargetGroup() - { - BuildTargetGroup group = EditorUserBuildSettings.selectedBuildTargetGroup; - if ((int)group == 0 || !BuildPlatforms.instance.ContainsBuildTarget(group)) - EditorUserBuildSettings.selectedBuildTargetGroup = BuildTargetGroup.Standalone; - } - static bool IsAnyStandaloneModuleLoaded() { return ModuleManager.IsPlatformSupportLoadedByBuildTarget(BuildTarget.StandaloneLinux64) || @@ -471,7 +467,6 @@ static bool IsLightmapEncodingValid(BuildPlatform platform) { "OSXStandalone", "Mac" }, { "WindowsStandalone", "Windows" }, { "LinuxStandalone", "Linux" }, - { "Facebook", "Facebook-Games"}, { "UWP", "Universal-Windows-Platform"} }; static public string GetPlaybackEngineDownloadURL(string moduleName) @@ -663,7 +658,7 @@ void ShowBuildTargetSettings() if (BuildPipeline.IsBuildTargetSupported(buildTargetGroup, buildTarget)) { - bool shouldDrawConnectProfilerToggle = buildWindowExtension != null ? buildWindowExtension.ShouldDrawProfilerCheckbox() : true; + bool shouldDrawProfilerToggles = buildWindowExtension != null ? buildWindowExtension.ShouldDrawProfilerCheckbox() : true; GUI.enabled = shouldDrawDevelopmentPlayerToggle; if (shouldDrawDevelopmentPlayerToggle) @@ -673,16 +668,15 @@ void ShowBuildTargetSettings() GUI.enabled = developmentBuild; - if (shouldDrawConnectProfilerToggle) + if (shouldDrawProfilerToggles) { - if (!GUI.enabled) - { - if (!developmentBuild) - styles.profileBuild.tooltip = "Profiling only enabled in Development Player"; - } - else - styles.profileBuild.tooltip = ""; - EditorUserBuildSettings.connectProfiler = EditorGUILayout.Toggle(styles.profileBuild, EditorUserBuildSettings.connectProfiler); + var profilerDisabled = !GUI.enabled && !developmentBuild; + + var autoConnectLabel = profilerDisabled ? styles.autoconnectProfilerDisabled : styles.autoconnectProfiler; + EditorUserBuildSettings.connectProfiler = EditorGUILayout.Toggle(autoConnectLabel, EditorUserBuildSettings.connectProfiler); + + var buildWithDeepProfilerLabel = profilerDisabled ? styles.buildWithDeepProfilerDisabled : styles.buildWithDeepProfiler; + EditorUserBuildSettings.buildWithDeepProfilingSupport = EditorGUILayout.Toggle(buildWithDeepProfilerLabel, EditorUserBuildSettings.buildWithDeepProfilingSupport); } GUI.enabled = developmentBuild; @@ -762,6 +756,8 @@ void ShowBuildTargetSettings() if (postprocessor != null && postprocessor.SupportsLz4Compression()) { var cmpIdx = Array.IndexOf(styles.compressionTypes, EditorUserBuildSettings.GetCompressionType(buildTargetGroup)); + if (cmpIdx == -1) + cmpIdx = Array.IndexOf(styles.compressionTypes, postprocessor.GetDefaultCompression()); if (cmpIdx == -1) cmpIdx = 1; // Lz4 by default. cmpIdx = EditorGUILayout.Popup(styles.compressionMethod, cmpIdx, styles.compressionStrings); diff --git a/Editor/Mono/BuildPlayerWindowBuildMethods.cs b/Editor/Mono/BuildPlayerWindowBuildMethods.cs index c9e1e2490a..c935003e08 100644 --- a/Editor/Mono/BuildPlayerWindowBuildMethods.cs +++ b/Editor/Mono/BuildPlayerWindowBuildMethods.cs @@ -234,9 +234,12 @@ internal static BuildPlayerOptions GetBuildPlayerOptionsInternal(bool askForBuil //Check if Lz4 is supported for the current buildtargetgroup and enable it if need be if (PostprocessBuildPlayer.SupportsLz4Compression(buildTargetGroup, buildTarget)) { - if (EditorUserBuildSettings.GetCompressionType(buildTargetGroup) == Compression.Lz4) + var compression = EditorUserBuildSettings.GetCompressionType(buildTargetGroup); + if (compression < 0) + compression = PostprocessBuildPlayer.GetDefaultCompression(buildTargetGroup, buildTarget); + if (compression == Compression.Lz4) options.options |= BuildOptions.CompressWithLz4; - else if (EditorUserBuildSettings.GetCompressionType(buildTargetGroup) == Compression.Lz4HC) + else if (compression == Compression.Lz4HC) options.options |= BuildOptions.CompressWithLz4HC; } @@ -251,6 +254,8 @@ internal static BuildPlayerOptions GetBuildPlayerOptionsInternal(bool askForBuil options.options |= BuildOptions.EnableHeadlessMode; if (EditorUserBuildSettings.connectProfiler && (developmentBuild || buildTarget == BuildTarget.WSAPlayer)) options.options |= BuildOptions.ConnectWithProfiler; + if (EditorUserBuildSettings.buildWithDeepProfilingSupport && developmentBuild) + options.options |= BuildOptions.EnableDeepProfilingSupport; if (EditorUserBuildSettings.buildScriptsOnly) options.options |= BuildOptions.BuildScriptsOnly; diff --git a/Editor/Mono/BuildTargetDiscovery.bindings.cs b/Editor/Mono/BuildTargetDiscovery.bindings.cs index a78920529c..3a927494ad 100644 --- a/Editor/Mono/BuildTargetDiscovery.bindings.cs +++ b/Editor/Mono/BuildTargetDiscovery.bindings.cs @@ -34,6 +34,7 @@ public enum TargetAttributes ReflectionEmitDisabled = (1 << 9), OSFontsDisabled = (1 << 10), NoDefaultUnityFonts = (1 << 11), + [Obsolete("Facebook support was removed in 2019.3")] SupportsFacebook = (1 << 12), WarnForMouseEvents = (1 << 13), HideInUI = (1 << 14), @@ -128,9 +129,6 @@ public static bool BuildTargetSupportsRenderer(BuildPlatform platform, GraphicsD public static string GetBuildTargetNiceName(BuildTarget platform, BuildTargetGroup buildTargetGroup = BuildTargetGroup.Unknown) { - if (PlatformHasFlag(platform, TargetAttributes.SupportsFacebook) && buildTargetGroup == BuildTargetGroup.Facebook) - return "Facebook"; - return GetNiceNameByBuildTarget(platform); } diff --git a/Editor/Mono/BuildTargetGroup.cs b/Editor/Mono/BuildTargetGroup.cs index 527ca00a98..d191bbd2e1 100644 --- a/Editor/Mono/BuildTargetGroup.cs +++ b/Editor/Mono/BuildTargetGroup.cs @@ -90,6 +90,7 @@ public enum BuildTargetGroup tvOS = 25, + [Obsolete("Facebook support was removed in 2019.3")] Facebook = 26, Switch = 27, diff --git a/Editor/Mono/CodeEditor/CodeEditor.cs b/Editor/Mono/CodeEditor/CodeEditor.cs index 1539af0a2f..492fb8cfab 100644 --- a/Editor/Mono/CodeEditor/CodeEditor.cs +++ b/Editor/Mono/CodeEditor/CodeEditor.cs @@ -41,6 +41,12 @@ 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; @@ -150,7 +156,7 @@ internal Dictionary GetFoundScriptEditorPaths() return result; } - static void AddIfPathExists(string name, string path, Dictionary list) + internal static void AddIfPathExists(string name, string path, Dictionary list) { if (list.ContainsKey(path)) return; @@ -170,6 +176,11 @@ 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 => Editor.EditorInstallation.Path; diff --git a/Editor/Mono/CodeEditor/CodeEditorProjectSync.cs b/Editor/Mono/CodeEditor/CodeEditorProjectSync.cs index eb7e43a839..f5376fb2b3 100644 --- a/Editor/Mono/CodeEditor/CodeEditorProjectSync.cs +++ b/Editor/Mono/CodeEditor/CodeEditorProjectSync.cs @@ -53,7 +53,15 @@ static void OpenProjectFileUnlessInBatchMode() if (InternalEditorUtility.inBatchMode) return; - CodeEditor.Editor.Current.OpenProject(); + #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/SyncVS.cs b/Editor/Mono/CodeEditor/SyncVS.cs index 800284f227..6cefc73066 100644 --- a/Editor/Mono/CodeEditor/SyncVS.cs +++ b/Editor/Mono/CodeEditor/SyncVS.cs @@ -5,16 +5,27 @@ using System; using System.Security.Cryptography; using System.Text; +using Unity.CodeEditor; +using UnityEditorInternal; namespace UnityEditor { - class SyncVS + 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(); + } } } diff --git a/Editor/Mono/Collab/Softlocks/SoftlockData.cs b/Editor/Mono/Collab/Softlocks/SoftlockData.cs index 7360fabff8..759a931cd0 100644 --- a/Editor/Mono/Collab/Softlocks/SoftlockData.cs +++ b/Editor/Mono/Collab/Softlocks/SoftlockData.cs @@ -5,11 +5,8 @@ using System; using System.Collections.Generic; -using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.Scripting; -using UnityEditor.Utils; -using UnityEditor.Web; namespace UnityEditor.Collaboration { @@ -67,13 +64,6 @@ public static bool IsPrefab(string assetGUID) return isPrefab; } - private static bool TryHasSoftLocks(Scene scene, out bool hasSoftLocks) - { - string assetGUID = AssetDatabase.AssetPathToGUID(scene.path); - bool success = TryHasSoftLocks(assetGUID, out hasSoftLocks); - return success; - } - // Soft locks are present when collab is enabled and other users are // editing the given object. // Failure: assigns false to 'hasSoftLocks', returns false. @@ -145,22 +135,6 @@ public static bool TryGetSoftlockCount(string assetGuid, out int count) return success; } - private static bool TryGetLocksOnObject(UnityEngine.Object objectWithGUID, out List softLocks) - { - bool success = false; - string assetGUID = null; - - if (AssetAccess.TryGetAssetGUIDFromObject(objectWithGUID, out assetGUID)) - { - success = TryGetLocksOnAssetGUID(assetGUID, out softLocks); - } - else - { - softLocks = new List(); - } - return success; - } - // Provides a list of 'SoftLock' items, representing // the additional users editing the given assetGUID. // Failure: assigns empty list to 'softLocks', return false. diff --git a/Editor/Mono/CollectImportedDependenciesAttribute.cs b/Editor/Mono/CollectImportedDependenciesAttribute.cs new file mode 100644 index 0000000000..de888b2f5f --- /dev/null +++ b/Editor/Mono/CollectImportedDependenciesAttribute.cs @@ -0,0 +1,108 @@ +// 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 System.Reflection; +using UnityEngine.Scripting; +using static UnityEditor.AttributeHelper; + +namespace UnityEditor.Experimental.AssetImporters +{ + [RequiredByNativeCode] + [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = true)] + public class CollectImportedDependenciesAttribute : Attribute + { + private Type m_ImporterType; + private uint m_Version; + + public CollectImportedDependenciesAttribute(Type importerType, uint version) + { + m_ImporterType = importerType; + m_Version = version; + } + + public Type importerType { get { return m_ImporterType; } } + public uint version { get { return m_Version; } } + + [RequiredSignature] + static extern string[] CollectImportedDependenciesSignature(string assetPath); + } + + static class ImportedDependenciesApi + { + static Dictionary s_ImportDependenciesHashStringMap = null; + static Dictionary s_ImportDependencyCallbackTypeMap = null; + + private static IEnumerable GetImportedDependenciesCallbacksAndAttributesForImporter(Type importerType) + { + if (s_ImportDependencyCallbackTypeMap != null && s_ImportDependencyCallbackTypeMap.ContainsKey(importerType)) + return s_ImportDependencyCallbackTypeMap[importerType]; + + if (s_ImportDependencyCallbackTypeMap == null) + s_ImportDependencyCallbackTypeMap = new Dictionary(); + + Func filter = (a) => a.importerType.IsAssignableFrom(importerType); + s_ImportDependencyCallbackTypeMap[importerType] = AttributeHelper.GetMethodsWithAttribute(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) + .methodsWithAttributes + .Where(x => filter((CollectImportedDependenciesAttribute)x.attribute)) + .ToArray(); + + return s_ImportDependencyCallbackTypeMap[importerType]; + } + + [RequiredByNativeCode] + private static MethodInfo[] GetImportedDependenciesCallbacks(Type importerType) + { + return GetImportedDependenciesCallbacksAndAttributesForImporter(importerType).Select(x => x.info).ToArray(); + } + + private static string BuildHashString(SortedList list) + { + var hashStr = ""; + foreach (var pair in list) + { + hashStr += pair.Key; + hashStr += '.'; + hashStr += pair.Value; + hashStr += '|'; + } + + return hashStr; + } + + [RequiredByNativeCode] + static string GetImportedDependenciesCallbacksHashString(Type importerType) + { + if (s_ImportDependenciesHashStringMap != null && s_ImportDependenciesHashStringMap.ContainsKey(importerType)) + return s_ImportDependenciesHashStringMap[importerType]; + + if (s_ImportDependenciesHashStringMap == null) + s_ImportDependenciesHashStringMap = new Dictionary(); + + var versionsByType = new SortedList(); + + var methodsWithAttribute = GetImportedDependenciesCallbacksAndAttributesForImporter(importerType); + + foreach (var method in methodsWithAttribute) + { + var attribute = (CollectImportedDependenciesAttribute)method.attribute; + var version = attribute.version; + string methodName = method.info.Name; + string className = method.info.ReflectedType.FullName; + + string fullMethodName = className + "." + methodName; + + if (version != 0) + { + versionsByType.Add(fullMethodName, version); + } + } + + s_ImportDependenciesHashStringMap[importerType] = BuildHashString(versionsByType); + return s_ImportDependenciesHashStringMap[importerType]; + } + } +} diff --git a/Editor/Mono/ContainerWindow.cs b/Editor/Mono/ContainerWindow.cs index 16c1e125b4..b03709f28b 100644 --- a/Editor/Mono/ContainerWindow.cs +++ b/Editor/Mono/ContainerWindow.cs @@ -192,7 +192,7 @@ internal bool IsNotDocked() return ( // hallelujah (m_ShowMode == (int)ShowMode.Utility || m_ShowMode == (int)ShowMode.AuxWindow) || - + (m_ShowMode == (int)ShowMode.MainWindow && rootView is HostView) || (rootView is SplitView && rootView.children.Length == 1 && rootView.children[0] is DockArea && @@ -214,18 +214,25 @@ private string NotDockedWindowID() return rootView.GetType().ToString(); } + if (rootView.children.Length > 0) + return (m_ShowMode == (int)ShowMode.Utility || m_ShowMode == (int)ShowMode.AuxWindow) ? v.actualView.GetType().ToString() + : ((DockArea)rootView.children[0]).m_Panes[0].GetType().ToString(); - return (m_ShowMode == (int)ShowMode.Utility || m_ShowMode == (int)ShowMode.AuxWindow) ? v.actualView.GetType().ToString() - : ((DockArea)rootView.children[0]).m_Panes[0].GetType().ToString(); + return v.actualView.GetType().ToString(); } return null; } + public bool IsMainWindow() + { + return m_ShowMode == (int)ShowMode.MainWindow && m_DontSaveToLayout == false; + } + public void Save() { // only save it if its not docked and its not the MainWindow - if ((m_ShowMode != (int)ShowMode.MainWindow) && IsNotDocked() && !IsZoomed()) + if (!IsMainWindow() && IsNotDocked() && !IsZoomed()) { string ID = NotDockedWindowID(); @@ -239,7 +246,7 @@ public void Save() private void Load(bool loadPosition) { - if ((m_ShowMode != (int)ShowMode.MainWindow) && IsNotDocked()) + if (!IsMainWindow() && IsNotDocked()) { string ID = NotDockedWindowID(); @@ -338,26 +345,6 @@ internal Rect GetDropDownRect(Rect buttonRect, Vector2 minSize, Vector2 maxSize) return PopupLocationHelper.GetDropDownRect(buttonRect, minSize, maxSize, this); } - internal Rect FitPopupWindowRectToScreen(Rect rect, float minimumHeight) - { - const float maxHeight = 900; - float spaceFromBottom = 0f; - if (Application.platform == RuntimePlatform.OSXEditor) - spaceFromBottom = 10f; - - float minHeight = minimumHeight + spaceFromBottom; - Rect p = rect; - p.height = Mathf.Min(p.height, maxHeight); - p.height += spaceFromBottom; - p = FitWindowRectToScreen(p, true, true); - - float newHeight = Mathf.Max(p.yMax - rect.y, minHeight); - p.y = p.yMax - newHeight; - p.height = newHeight - spaceFromBottom; - - return p; - } - public void HandleWindowDecorationEnd(Rect windowPosition) { // No Op diff --git a/Editor/Mono/DragAndDropService.cs b/Editor/Mono/DragAndDropService.cs index 39409c65d9..3b0ac6e5ae 100644 --- a/Editor/Mono/DragAndDropService.cs +++ b/Editor/Mono/DragAndDropService.cs @@ -86,6 +86,8 @@ public static void RemoveDropHandler(int dropDstId, Delegate handler) public static DragAndDropVisualMode Drop(int dropDstId, params object[] args) { List handlers; + SavedGUIState guiState = SavedGUIState.Create(); + if (!m_DropDescriptors.TryGetValue(dropDstId, out handlers)) { return DragAndDropVisualMode.Rejected; @@ -102,6 +104,7 @@ public static DragAndDropVisualMode Drop(int dropDstId, params object[] args) } } + guiState.ApplyAndForget(); return dropResult; } diff --git a/Editor/Mono/EditorApplication.cs b/Editor/Mono/EditorApplication.cs index 09d1fba52b..457139c438 100644 --- a/Editor/Mono/EditorApplication.cs +++ b/Editor/Mono/EditorApplication.cs @@ -11,6 +11,7 @@ using UnityEngine.Scripting; using UnityEditorInternal; using UnityEngine.TestTools; +using Unity.Profiling; namespace UnityEditor { @@ -304,7 +305,16 @@ internal static string BuildMainWindowTitle() static void Internal_CallUpdateFunctions() { if (update != null) - update(); + { + var invocationList = update.GetInvocationList(); + foreach (var cb in invocationList) + { + var marker = new ProfilerMarker(cb.Method.Name); + marker.Begin(); + cb.DynamicInvoke(); + marker.End(); + } + } } static void Internal_CallDelayFunctions() diff --git a/Editor/Mono/EditorGUI.cs b/Editor/Mono/EditorGUI.cs index 697f81fc88..4590a549c0 100644 --- a/Editor/Mono/EditorGUI.cs +++ b/Editor/Mono/EditorGUI.cs @@ -3,11 +3,9 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; -using System.Linq; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Globalization; -using System.Reflection; using System.Text.RegularExpressions; using UnityEditor.SceneManagement; using UnityEngine; @@ -148,7 +146,6 @@ public sealed partial class EditorGUI private static Color k_OverrideMarginColor = new Color(1f / 255f, 153f / 255f, 235f / 255f, 0.75f); - private const int kInspTitlebarToggleWidth = 16; private const int kInspTitlebarSpacing = 4; private static readonly GUIContent s_PropertyFieldTempContent = new GUIContent(); private static GUIContent s_IconDropDown; @@ -1906,7 +1903,7 @@ internal static void DragNumberValue(Rect dragHotZone, int id, bool isDouble, re switch (evt.GetTypeForControl(id)) { case EventType.MouseDown: - if (dragHotZone.Contains(evt.mousePosition) && evt.button == 0) + if (GUIUtility.HitTest(dragHotZone, evt) && evt.button == 0) { // When clicking the dragging rect ensure that the number field is not // editing: otherwise we don't see the actual value but the edited temp value @@ -2580,7 +2577,8 @@ internal static int IntSlider(Rect position, int value, int leftValue, int right public static int IntSlider(Rect position, int value, int leftValue, int rightValue) { - return IntSlider(position, value, leftValue, rightValue); + int id = GUIUtility.GetControlID(s_SliderHash, FocusType.Keyboard, position); + return Mathf.RoundToInt(DoSlider(IndentedRect(position), EditorGUIUtility.DragZoneRect(position), id, value, leftValue, rightValue, kIntFieldFormatString)); } public static int IntSlider(Rect position, string label, int value, int leftValue, int rightValue) @@ -5928,7 +5926,7 @@ internal static void DrawPreviewTextureInternal(Rect position, Texture image, Ma } // This will return appriopriate material to use with the texture according to its usage mode - internal static Material GetMaterialForSpecialTexture(Texture t, Material defaultMat = null) + internal static Material GetMaterialForSpecialTexture(Texture t, Material defaultMat = null, bool normals2Linear = false) { // i am not sure WHY do we check that (i would guess this is api user error and exception make sense, not "return something") if (t == null) return null; @@ -5942,7 +5940,10 @@ internal static Material GetMaterialForSpecialTexture(Texture t, Material defaul else if (usage == TextureUsageMode.BakedLightmapFullHDR) return lightmapFullHDRMaterial; else if (usage == TextureUsageMode.NormalmapDXT5nm || (usage == TextureUsageMode.NormalmapPlain && format == TextureFormat.BC5)) + { + normalmapMaterial.SetFloat("_ManualTex2Linear", normals2Linear ? 1.0f : 0.0f); return normalmapMaterial; + } else if (TextureUtil.IsAlphaOnlyTextureFormat(format)) return alphaMaterial; return defaultMat; @@ -6439,7 +6440,7 @@ internal static bool DropdownButton(int id, Rect position, GUIContent content, G style.Draw(position, content, id, false, hovered); break; case EventType.MouseDown: - if (position.Contains(evt.mousePosition) && evt.button == 0) + if (GUIUtility.HitTest(position, evt) && evt.button == 0) { Event.current.Use(); return true; diff --git a/Editor/Mono/EditorGUIUtility.bindings.cs b/Editor/Mono/EditorGUIUtility.bindings.cs index 3edfbd8d59..feccfbbfd6 100644 --- a/Editor/Mono/EditorGUIUtility.bindings.cs +++ b/Editor/Mono/EditorGUIUtility.bindings.cs @@ -150,7 +150,8 @@ public static void RenderGameViewCameras(RenderTexture target, int targetDisplay internal static extern Texture2D GetIconForObject(Object obj); // Render all ingame cameras bound to a specific Display. - internal static extern void RenderGameViewCamerasInternal(RenderTexture target, int targetDisplay, Rect screenRect, Vector2 mousePosition, bool gizmos, bool sendInput); + internal static extern void RenderPreviewCamerasInternal(RenderTexture target, int targetDisplay, Vector2 mousePosition, bool gizmos, bool renderIMGUI); + internal static extern void SetupWindowSpaceAndVSyncInternal(Rect screenRect); private static extern Texture2D FindTextureByName(string name); private static extern Texture2D FindTextureByType([NotNull] Type type); diff --git a/Editor/Mono/EditorGUIUtility.cs b/Editor/Mono/EditorGUIUtility.cs index cd39db6c8d..03c968746e 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; } diff --git a/Editor/Mono/EditorHandles/ArcHandle.cs b/Editor/Mono/EditorHandles/ArcHandle.cs index 0fbb4f42bb..3e6c18136d 100644 --- a/Editor/Mono/EditorHandles/ArcHandle.cs +++ b/Editor/Mono/EditorHandles/ArcHandle.cs @@ -3,6 +3,7 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System.Collections.Generic; +using UnityEditor.Snap; using UnityEngine; namespace UnityEditor.IMGUI.Controls @@ -185,7 +186,7 @@ public void DrawHandle() Vector3.forward, size, radiusHandleDrawFunction, - SnapSettings.move.z + EditorSnapSettings.move.z ); } if (EditorGUI.EndChangeCheck()) @@ -222,7 +223,7 @@ public void DrawHandle() float newAngle = Vector3.Angle(Vector3.forward, angleHandlePosition) * Mathf.Sign(Vector3.Dot(Vector3.right, angleHandlePosition)); angle += Mathf.DeltaAngle(angle, newAngle); - angle = Handles.SnapValue(angle, SnapSettings.rotation); + angle = Handles.SnapValue(angle, EditorSnapSettings.rotate); } } } diff --git a/Editor/Mono/EditorHandles/BoundsHandle/PrimitiveBoundsHandle.cs b/Editor/Mono/EditorHandles/BoundsHandle/PrimitiveBoundsHandle.cs index 075a3b1b07..e4169dbd00 100644 --- a/Editor/Mono/EditorHandles/BoundsHandle/PrimitiveBoundsHandle.cs +++ b/Editor/Mono/EditorHandles/BoundsHandle/PrimitiveBoundsHandle.cs @@ -4,6 +4,7 @@ using UnityEngine; using System; +using UnityEditor.Snap; namespace UnityEditor.IMGUI.Controls { @@ -291,9 +292,7 @@ private Vector3 MidpointHandle(int id, Vector3 localPos, Vector3 localTangent, V var size = midpointHandleSizeFunction == null ? 0f : midpointHandleSizeFunction(localPos); - localPos = UnityEditorInternal.Slider1D.Do( - id, localPos, localDir, size, midpointHandleDrawFunction, SnapSettings.scale - ); + localPos = UnityEditorInternal.Slider1D.Do(id, localPos, localDir, size, midpointHandleDrawFunction, EditorSnapSettings.scale); } Handles.color = oldColor; @@ -304,7 +303,7 @@ private void AdjustMidpointHandleColor(Vector3 localPos, Vector3 localTangent, V { float alphaMultiplier = 1f; - // if inside the box then ignore backfacing alpha multiplier (otherwise all handles will look disabled) + // if inside the box then ignore back facing alpha multiplier (otherwise all handles will look disabled) if (!isCameraInsideBox && axes == (Axes.X | Axes.Y | Axes.Z)) { // use tangent and binormal to calculate normal in case handle matrix is skewed @@ -312,7 +311,7 @@ private void AdjustMidpointHandleColor(Vector3 localPos, Vector3 localTangent, V Vector3 worldBinormal = Handles.matrix.MultiplyVector(localBinormal); Vector3 worldDir = Vector3.Cross(worldTangent, worldBinormal).normalized; - // adjust color if handle is backfacing + // adjust color if handle is back facing float cosV; if (Camera.current.orthographic) diff --git a/Editor/Mono/EditorHandles/Disc.cs b/Editor/Mono/EditorHandles/Disc.cs index b9dd7bcb18..46c91133a9 100644 --- a/Editor/Mono/EditorHandles/Disc.cs +++ b/Editor/Mono/EditorHandles/Disc.cs @@ -3,6 +3,7 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using UnityEditor; +using UnityEditor.Snap; using UnityEngine; namespace UnityEditorInternal @@ -74,6 +75,7 @@ public static Quaternion Do(int id, Quaternion rotation, Vector3 position, Vecto EditorGUIUtility.SetWantsMouseJumping(1); } break; + case EventType.MouseDrag: if (GUIUtility.hotControl == id) { @@ -105,6 +107,7 @@ public static Quaternion Do(int id, Quaternion rotation, Vector3 position, Vecto evt.Use(); } break; + case EventType.MouseUp: if (GUIUtility.hotControl == id && (evt.button == 0 || evt.button == 2)) { @@ -114,10 +117,12 @@ public static Quaternion Do(int id, Quaternion rotation, Vector3 position, Vecto EditorGUIUtility.SetWantsMouseJumping(0); } break; + case EventType.MouseMove: if (id == HandleUtility.nearestControl) HandleUtility.Repaint(); break; + case EventType.KeyDown: if (evt.keyCode == KeyCode.Escape && GUIUtility.hotControl == id) { @@ -126,6 +131,7 @@ public static Quaternion Do(int id, Quaternion rotation, Vector3 position, Vecto EditorGUIUtility.SetWantsMouseJumping(0); } break; + case EventType.Repaint: Color temp = Color.white; @@ -157,7 +163,7 @@ public static Quaternion Do(int id, Quaternion rotation, Vector3 position, Vecto Handles.DrawSolidArc(position, axis, from, d, size); // Draw snap markers - if (EditorGUI.actionKey && snap > 0) + if (EditorSnapSettings.active && snap > 0) { DrawRotationUnitSnapMarkers(position, axis, size, k_RotationUnitSnapMarkerSize, snap, @from); DrawRotationUnitSnapMarkers(position, axis, size, k_RotationUnitSnapMajorMarkerSize, k_RotationUnitSnapMajorMarkerStep, @from); diff --git a/Editor/Mono/EditorHandles/FreeMove.cs b/Editor/Mono/EditorHandles/FreeMove.cs index e2258efae0..caaf88d949 100644 --- a/Editor/Mono/EditorHandles/FreeMove.cs +++ b/Editor/Mono/EditorHandles/FreeMove.cs @@ -4,6 +4,7 @@ using System; using UnityEditor; +using UnityEditor.Snap; using UnityEngine; namespace UnityEditorInternal @@ -14,7 +15,7 @@ internal class FreeMove private static Vector3 s_StartPosition; // DrawCapFunction was marked plannned obsolete by @juha on 2016-03-16, marked obsolete warning by @adamm on 2016-12-21 - [Obsolete("DrawCapFunction is obsolete. Use the version with CapFunction instead. Example: Change SphereCap to SphereHandleCap.")] + [Obsolete("DrawCapFunction is obsolete. Use the version with CapFunction instead. Example: Change SphereCap to SphereHandleCap.", true)] #pragma warning disable 618 public static Vector3 Do(int id, Vector3 position, Quaternion rotation, float size, Vector3 snap, Handles.DrawCapFunction capFunc) #pragma warning restore 618 @@ -33,6 +34,7 @@ public static Vector3 Do(int id, Vector3 position, Quaternion rotation, float si HandleUtility.AddControl(id, HandleUtility.DistanceToCircle(worldPosition, size * 1.2f)); Handles.matrix = origMatrix; break; + case EventType.MouseDown: // am I closest to the thingy? if (HandleUtility.nearestControl == id && evt.button == 0) @@ -45,6 +47,7 @@ public static Vector3 Do(int id, Vector3 position, Quaternion rotation, float si EditorGUIUtility.SetWantsMouseJumping(1); } break; + case EventType.MouseDrag: if (GUIUtility.hotControl == id) { @@ -98,9 +101,7 @@ public static Vector3 Do(int id, Vector3 position, Quaternion rotation, float si if (EditorGUI.actionKey && !evt.shift) { Vector3 delta = position - s_StartPosition; - delta.x = Handles.SnapValue(delta.x, snap.x); - delta.y = Handles.SnapValue(delta.y, snap.y); - delta.z = Handles.SnapValue(delta.z, snap.z); + delta = Handles.SnapValue(delta, snap); position = s_StartPosition + delta; } } @@ -108,6 +109,7 @@ public static Vector3 Do(int id, Vector3 position, Quaternion rotation, float si evt.Use(); } break; + case EventType.MouseUp: if (GUIUtility.hotControl == id && (evt.button == 0 || evt.button == 2)) { @@ -117,10 +119,12 @@ public static Vector3 Do(int id, Vector3 position, Quaternion rotation, float si EditorGUIUtility.SetWantsMouseJumping(0); } break; + case EventType.MouseMove: if (id == HandleUtility.nearestControl) HandleUtility.Repaint(); break; + case EventType.Repaint: Color temp = Color.white; @@ -163,6 +167,7 @@ public static Vector3 Do(int id, Vector3 position, Quaternion rotation, float si handleFunction(id, worldPosition, Camera.current.transform.rotation, size, EventType.Layout); Handles.matrix = origMatrix; break; + case EventType.MouseDown: // am I closest to the thingy? if (HandleUtility.nearestControl == id && evt.button == 0) @@ -175,6 +180,7 @@ public static Vector3 Do(int id, Vector3 position, Quaternion rotation, float si EditorGUIUtility.SetWantsMouseJumping(1); } break; + case EventType.MouseDrag: if (GUIUtility.hotControl == id) { @@ -225,12 +231,10 @@ public static Vector3 Do(int id, Vector3 position, Quaternion rotation, float si } } - if (EditorGUI.actionKey && !evt.shift) + if (EditorSnapSettings.active && !evt.shift) { Vector3 delta = position - s_StartPosition; - delta.x = Handles.SnapValue(delta.x, snap.x); - delta.y = Handles.SnapValue(delta.y, snap.y); - delta.z = Handles.SnapValue(delta.z, snap.z); + delta = Handles.SnapValue(delta, snap); position = s_StartPosition + delta; } } @@ -238,6 +242,7 @@ public static Vector3 Do(int id, Vector3 position, Quaternion rotation, float si evt.Use(); } break; + case EventType.MouseUp: if (GUIUtility.hotControl == id && (evt.button == 0 || evt.button == 2)) { @@ -247,10 +252,12 @@ public static Vector3 Do(int id, Vector3 position, Quaternion rotation, float si EditorGUIUtility.SetWantsMouseJumping(0); } break; + case EventType.MouseMove: if (id == HandleUtility.nearestControl) HandleUtility.Repaint(); break; + case EventType.Repaint: Color temp = Color.white; diff --git a/Editor/Mono/EditorHandles/PositionHandle.cs b/Editor/Mono/EditorHandles/PositionHandle.cs index 77ee6a60fc..bbee5df462 100644 --- a/Editor/Mono/EditorHandles/PositionHandle.cs +++ b/Editor/Mono/EditorHandles/PositionHandle.cs @@ -3,6 +3,7 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; +using UnityEditor.Snap; using UnityEngine; namespace UnityEditor @@ -320,7 +321,7 @@ static Vector3 DoPositionHandle_Internal(PositionHandleIds ids, Vector3 position s_DoPositionHandle_ArrowCapConeOffset = isHot ? rotation * Vector3.Scale(Vector3.Scale(axisVector, param.axisOffset), s_DoPositionHandle_AxisHandlesOctant) : Vector3.zero; - position = Slider(ids[i], position, offset, dir, size * param.axisSize[i], DoPositionHandle_ArrowCap, GridSnapping.active ? 0f : SnapSettings.move[i]); + position = Slider(ids[i], position, offset, dir, size * param.axisSize[i], DoPositionHandle_ArrowCap, GridSnapping.active ? 0f : EditorSnapSettings.move[i]); } } @@ -329,14 +330,14 @@ static Vector3 DoPositionHandle_Internal(PositionHandleIds ids, Vector3 position { color = ToActiveColorSpace(centerColor); GUI.SetNextControlName("FreeMoveAxis"); - position = FreeMoveHandle(ids.xyz, position, rotation, size * kFreeMoveHandleSizeFactor, GridSnapping.active ? Vector3.zero : SnapSettings.move, RectangleHandleCap); + position = FreeMoveHandle(ids.xyz, position, rotation, size * kFreeMoveHandleSizeFactor, GridSnapping.active ? Vector3.zero : EditorSnapSettings.move, RectangleHandleCap); } - color = temp; - if (GridSnapping.active) position = GridSnapping.Snap(position); + color = temp; + return position; } @@ -438,7 +439,7 @@ static Vector3 DoPlanarHandle( axis1, axis2, handleSize * 0.5f, RectangleHandleCap, - GridSnapping.active ? Vector2.zero : new Vector2(SnapSettings.move[axis1index], SnapSettings.move[axis2index]), + GridSnapping.active ? Vector2.zero : new Vector2(EditorSnapSettings.move[axis1index], EditorSnapSettings.move[axis2index]), false); Handles.color = prevColor; diff --git a/Editor/Mono/EditorHandles/RotationHandle.cs b/Editor/Mono/EditorHandles/RotationHandle.cs index bfa5526fe6..9035be1bd8 100644 --- a/Editor/Mono/EditorHandles/RotationHandle.cs +++ b/Editor/Mono/EditorHandles/RotationHandle.cs @@ -3,6 +3,7 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; +using UnityEditor.Snap; using UnityEngine; namespace UnityEditor @@ -150,6 +151,7 @@ internal static Quaternion DoRotationHandle(RotationHandleIds ids, Quaternion ro } var radiusOfAxesHandles = -1f; + for (var i = 0; i < 3; ++i) { if (!param.ShouldShow(i)) @@ -163,7 +165,7 @@ internal static Quaternion DoRotationHandle(RotationHandleIds ids, Quaternion ro var radius = size * param.axisSize[i]; radiusOfAxesHandles = Mathf.Max(radius, radiusOfAxesHandles); - rotation = UnityEditorInternal.Disc.Do(ids[i], rotation, position, rotation * axisDir, radius, true, SnapSettings.rotation, param.enableRayDrag, true, k_RotationPieColor); + rotation = UnityEditorInternal.Disc.Do(ids[i], rotation, position, rotation * axisDir, radius, true, EditorSnapSettings.rotate, param.enableRayDrag, true, k_RotationPieColor); } if (radiusOfAxesHandles > 0 && evt.type == EventType.Repaint) diff --git a/Editor/Mono/EditorHandles/ScaleHandle.cs b/Editor/Mono/EditorHandles/ScaleHandle.cs index 7385194302..20b917db01 100644 --- a/Editor/Mono/EditorHandles/ScaleHandle.cs +++ b/Editor/Mono/EditorHandles/ScaleHandle.cs @@ -3,6 +3,7 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; +using UnityEditor.Snap; using UnityEngine; namespace UnityEditor @@ -205,7 +206,7 @@ internal static Vector3 DoScaleHandle(ScaleHandleIds ids, Vector3 scale, Vector3 rotation * axisDir, rotation, handleSize * param.axisSize[i], - SnapSettings.scale, + EditorSnapSettings.scale, offset, axisLineScale[i]); } @@ -215,7 +216,7 @@ 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); + var s = ScaleValueHandle(ids.xyz, scale.x, position, rotation, handleSize * param.xyzSize, CubeHandleCap, EditorSnapSettings.scale); if (EditorGUI.EndChangeCheck() && !Mathf.Approximately(scale.x, 0)) { var dif = s / scale.x; diff --git a/Editor/Mono/EditorHandles/Slider1D.cs b/Editor/Mono/EditorHandles/Slider1D.cs index cbe3a8f3b6..85a6e54c83 100644 --- a/Editor/Mono/EditorHandles/Slider1D.cs +++ b/Editor/Mono/EditorHandles/Slider1D.cs @@ -15,9 +15,9 @@ internal class Slider1D // DrawCapFunction was marked plannned obsolete by @juha on 2016-03-16, marked obsolete warning by @adamm on 2016-12-21 [Obsolete("DrawCapFunction is obsolete. Use the version with CapFunction instead. Example: Change SphereCap to SphereHandleCap.")] - #pragma warning disable 618 +#pragma warning disable 618 internal static Vector3 Do(int id, Vector3 position, Vector3 direction, float size, Handles.DrawCapFunction drawFunc, float snap) - #pragma warning restore 618 +#pragma warning restore 618 { return Do(id, position, direction, direction, size, drawFunc, snap); } @@ -29,9 +29,9 @@ internal static Vector3 Do(int id, Vector3 position, Vector3 direction, float si // DrawCapFunction was marked plannned obsolete by @juha on 2016-03-16, marked obsolete warning by @adamm on 2016-12-21 [Obsolete("DrawCapFunction is obsolete. Use the version with CapFunction instead. Example: Change SphereCap to SphereHandleCap.")] - #pragma warning disable 618 +#pragma warning disable 618 internal static Vector3 Do(int id, Vector3 position, Vector3 handleDirection, Vector3 slideDirection, float size, Handles.DrawCapFunction drawFunc, float snap) - #pragma warning disable 618 +#pragma warning disable 618 { Event evt = Event.current; switch (evt.GetTypeForControl(id)) @@ -48,6 +48,7 @@ internal static Vector3 Do(int id, Vector3 position, Vector3 handleDirection, Ve HandleUtility.AddControl(id, HandleUtility.DistanceToCircle(position, size * .2f)); } break; + case EventType.MouseDown: // am I closest to the thingy? if ((HandleUtility.nearestControl == id && evt.button == 0) && GUIUtility.hotControl == 0 && !evt.alt) @@ -60,6 +61,7 @@ internal static Vector3 Do(int id, Vector3 position, Vector3 handleDirection, Ve } break; + case EventType.MouseDrag: if (GUIUtility.hotControl == id) { @@ -75,6 +77,7 @@ internal static Vector3 Do(int id, Vector3 position, Vector3 handleDirection, Ve evt.Use(); } break; + case EventType.MouseUp: if (GUIUtility.hotControl == id && (evt.button == 0 || evt.button == 2)) { @@ -83,10 +86,12 @@ internal static Vector3 Do(int id, Vector3 position, Vector3 handleDirection, Ve EditorGUIUtility.SetWantsMouseJumping(0); } break; + case EventType.MouseMove: if (id == HandleUtility.nearestControl) HandleUtility.Repaint(); break; + case EventType.Repaint: Color temp = Color.white; @@ -120,6 +125,7 @@ internal static Vector3 Do(int id, Vector3 position, Vector3 offset, Vector3 han else HandleUtility.AddControl(id, HandleUtility.DistanceToCircle(position + offset, size * .2f)); break; + case EventType.MouseDown: // am I closest to the thingy? if (HandleUtility.nearestControl == id && evt.button == 0 && GUIUtility.hotControl == 0 && !evt.alt) @@ -132,6 +138,7 @@ internal static Vector3 Do(int id, Vector3 position, Vector3 offset, Vector3 han } break; + case EventType.MouseDrag: if (GUIUtility.hotControl == id) { @@ -142,11 +149,17 @@ internal static Vector3 Do(int id, Vector3 position, Vector3 offset, Vector3 han Vector3 worldDirection = Handles.matrix.MultiplyVector(slideDirection); Vector3 worldPosition = Handles.matrix.MultiplyPoint(s_StartPosition) + worldDirection * dist; + + if (EditorSnapSettings.active && EditorSnapSettings.preferGrid && Snapping.IsCardinalDirection(worldDirection)) + worldPosition = Handles.SnapValue(worldPosition, new SnapAxisFilter(worldDirection) * snap); + position = Handles.inverseMatrix.MultiplyPoint(worldPosition); + GUI.changed = true; evt.Use(); } break; + case EventType.MouseUp: if (GUIUtility.hotControl == id && (evt.button == 0 || evt.button == 2)) { @@ -155,10 +168,12 @@ internal static Vector3 Do(int id, Vector3 position, Vector3 offset, Vector3 han EditorGUIUtility.SetWantsMouseJumping(0); } break; + case EventType.MouseMove: if (id == HandleUtility.nearestControl) HandleUtility.Repaint(); break; + case EventType.Repaint: Color temp = Color.white; diff --git a/Editor/Mono/EditorHandles/Slider2D.cs b/Editor/Mono/EditorHandles/Slider2D.cs index dcb61a1aae..99ba7b064c 100644 --- a/Editor/Mono/EditorHandles/Slider2D.cs +++ b/Editor/Mono/EditorHandles/Slider2D.cs @@ -16,7 +16,7 @@ internal class Slider2D // DrawCapFunction was marked plannned obsolete by @juha on 2016-03-16, marked obsolete warning by @adamm on 2016-12-21 [Obsolete("DrawCapFunction is obsolete. Use the version with CapFunction instead. Example: Change SphereCap to SphereHandleCap.")] - #pragma warning disable 618 +#pragma warning disable 618 public static Vector3 Do( int id, Vector3 handlePos, @@ -27,14 +27,14 @@ public static Vector3 Do( Handles.DrawCapFunction drawFunc, float snap, bool drawHelper) - #pragma warning restore 618 +#pragma warning restore 618 { return Do(id, handlePos, new Vector3(0, 0, 0), handleDir, slideDir1, slideDir2, handleSize, drawFunc, new Vector2(snap, snap), drawHelper); } // DrawCapFunction was marked plannned obsolete by @juha on 2016-03-16, marked obsolete warning by @adamm on 2016-12-21 [Obsolete("DrawCapFunction is obsolete. Use the version with CapFunction instead. Example: Change SphereCap to SphereHandleCap.")] - #pragma warning disable 618 +#pragma warning disable 618 public static Vector3 Do( int id, Vector3 handlePos, @@ -46,14 +46,14 @@ public static Vector3 Do( Handles.DrawCapFunction drawFunc, float snap, bool drawHelper) - #pragma warning restore 618 +#pragma warning restore 618 { return Do(id, handlePos, offset, handleDir, slideDir1, slideDir2, handleSize, drawFunc, new Vector2(snap, snap), drawHelper); } // DrawCapFunction was marked plannned obsolete by @juha on 2016-03-16, marked obsolete warning by @adamm on 2016-12-21 [Obsolete("DrawCapFunction is obsolete. Use the version with CapFunction instead. Example: Change SphereCap to SphereHandleCap.")] - #pragma warning disable 618 +#pragma warning disable 618 public static Vector3 Do( int id, Vector3 handlePos, @@ -65,15 +65,30 @@ public static Vector3 Do( Handles.DrawCapFunction drawFunc, Vector2 snap, bool drawHelper) - #pragma warning restore 618 +#pragma warning restore 618 { bool orgGuiChanged = GUI.changed; GUI.changed = false; Vector2 delta = CalcDeltaAlongDirections(id, handlePos, offset, handleDir, slideDir1, slideDir2, handleSize, drawFunc, snap, drawHelper); + if (GUI.changed) + { handlePos = s_StartPosition + slideDir1 * delta.x + slideDir2 * delta.y; + if (EditorSnapSettings.active && EditorSnapSettings.preferGrid) + { + var normal = Vector3.Cross(slideDir1, slideDir2); + + if (Snapping.IsCardinalDirection(normal)) + { + var worldSpace = Handles.matrix.MultiplyPoint(handlePos); + worldSpace = Handles.SnapValue(worldSpace, (~new SnapAxisFilter(normal)) * snap); + handlePos = Handles.inverseMatrix.MultiplyPoint(worldSpace); + } + } + } + GUI.changed |= orgGuiChanged; return handlePos; } @@ -127,15 +142,29 @@ public static Vector3 Do( Vector2 delta = CalcDeltaAlongDirections(id, handlePos, offset, handleDir, slideDir1, slideDir2, handleSize, capFunction, snap, drawHelper); if (GUI.changed) + { handlePos = s_StartPosition + slideDir1 * delta.x + slideDir2 * delta.y; + if (EditorSnapSettings.active && EditorSnapSettings.preferGrid) + { + var normal = Vector3.Cross(slideDir1, slideDir2); + + if (Snapping.IsCardinalDirection(normal)) + { + var worldSpace = Handles.matrix.MultiplyPoint(handlePos); + worldSpace = Handles.SnapValue(worldSpace, (~new SnapAxisFilter(normal)) * snap); + handlePos = Handles.inverseMatrix.MultiplyPoint(worldSpace); + } + } + } + GUI.changed |= orgGuiChanged; return handlePos; } - // DrawCapFunction was marked plannned obsolete by @juha on 2016-03-16, marked obsolete warning by @adamm on 2016-12-21 + // DrawCapFunction was marked planned obsolete by @juha on 2016-03-16, marked obsolete warning by @adamm on 2016-12-21 [Obsolete("DrawCapFunction is obsolete. Use the version with CapFunction instead. Example: Change SphereCap to SphereHandleCap.")] - #pragma warning disable 618 +#pragma warning disable 618 private static Vector2 CalcDeltaAlongDirections( int id, Vector3 handlePos, @@ -147,7 +176,7 @@ private static Vector2 CalcDeltaAlongDirections( Handles.DrawCapFunction drawFunc, Vector2 snap, bool drawHelper) - #pragma warning restore 618 +#pragma warning restore 618 { Vector2 deltaDistanceAlongDirections = new Vector2(0, 0); @@ -225,6 +254,7 @@ private static Vector2 CalcDeltaAlongDirections( evt.Use(); } break; + case EventType.MouseUp: if (GUIUtility.hotControl == id && (evt.button == 0 || evt.button == 2)) { @@ -233,10 +263,12 @@ private static Vector2 CalcDeltaAlongDirections( EditorGUIUtility.SetWantsMouseJumping(0); } break; + case EventType.MouseMove: if (id == HandleUtility.nearestControl) HandleUtility.Repaint(); break; + case EventType.Repaint: { if (drawFunc == null) @@ -312,6 +344,7 @@ private static Vector2 CalcDeltaAlongDirections( else HandleUtility.AddControl(id, HandleUtility.DistanceToCircle(handlePos + offset, handleSize * .5f)); break; + case EventType.MouseDown: // am I closest to the thingy? if (HandleUtility.nearestControl == id && evt.button == 0 && GUIUtility.hotControl == 0 && !evt.alt) @@ -333,6 +366,7 @@ private static Vector2 CalcDeltaAlongDirections( } } break; + case EventType.MouseDrag: if (GUIUtility.hotControl == id) { @@ -345,17 +379,15 @@ private static Vector2 CalcDeltaAlongDirections( deltaDistanceAlongDirections.x = HandleUtility.PointOnLineParameter(localMousePoint, s_StartPosition, slideDir1); deltaDistanceAlongDirections.y = HandleUtility.PointOnLineParameter(localMousePoint, s_StartPosition, slideDir2); deltaDistanceAlongDirections -= s_StartPlaneOffset; - if (snap.x > 0 || snap.y > 0) - { - deltaDistanceAlongDirections.x = Handles.SnapValue(deltaDistanceAlongDirections.x, snap.x); - deltaDistanceAlongDirections.y = Handles.SnapValue(deltaDistanceAlongDirections.y, snap.y); - } + deltaDistanceAlongDirections.x = Handles.SnapValue(deltaDistanceAlongDirections.x, snap.x); + deltaDistanceAlongDirections.y = Handles.SnapValue(deltaDistanceAlongDirections.y, snap.y); GUI.changed = true; } evt.Use(); } break; + case EventType.MouseUp: if (GUIUtility.hotControl == id && (evt.button == 0 || evt.button == 2)) { @@ -364,10 +396,12 @@ private static Vector2 CalcDeltaAlongDirections( EditorGUIUtility.SetWantsMouseJumping(0); } break; + case EventType.MouseMove: if (id == HandleUtility.nearestControl) HandleUtility.Repaint(); break; + case EventType.Repaint: { if (capFunction == null) diff --git a/Editor/Mono/EditorHandles/SliderScale.cs b/Editor/Mono/EditorHandles/SliderScale.cs index d9a3dfd452..9f8eab60f9 100644 --- a/Editor/Mono/EditorHandles/SliderScale.cs +++ b/Editor/Mono/EditorHandles/SliderScale.cs @@ -4,6 +4,7 @@ using System; using UnityEditor; +using UnityEditor.Snap; using UnityEngine; namespace UnityEditorInternal @@ -35,6 +36,7 @@ internal static float DoAxis(int id, float scale, Vector3 position, Vector3 dire HandleUtility.AddControl(id, HandleUtility.DistanceToLine(startPosition, cubePosition)); HandleUtility.AddControl(id, HandleUtility.DistanceToCircle(cubePosition, size * .3f)); break; + case EventType.MouseDown: // am I closest to the thingy? if (HandleUtility.nearestControl == id && evt.button == 0 && !evt.alt) @@ -46,6 +48,7 @@ internal static float DoAxis(int id, float scale, Vector3 position, Vector3 dire EditorGUIUtility.SetWantsMouseJumping(1); } break; + case EventType.MouseDrag: if (GUIUtility.hotControl == id) { @@ -57,6 +60,7 @@ internal static float DoAxis(int id, float scale, Vector3 position, Vector3 dire evt.Use(); } break; + case EventType.MouseUp: if (GUIUtility.hotControl == id && (evt.button == 0 || evt.button == 2)) { @@ -65,10 +69,12 @@ internal static float DoAxis(int id, float scale, Vector3 position, Vector3 dire EditorGUIUtility.SetWantsMouseJumping(0); } break; + case EventType.MouseMove: if (id == HandleUtility.nearestControl) HandleUtility.Repaint(); break; + case EventType.Repaint: Color temp = Color.white; if (id == GUIUtility.hotControl) @@ -95,9 +101,9 @@ internal static float DoAxis(int id, float scale, Vector3 position, Vector3 dire // DrawCapFunction was marked plannned obsolete by @juha on 2016-03-16, marked obsolete warning by @adamm on 2016-12-21 [Obsolete("DrawCapFunction is obsolete. Use the version with CapFunction instead. Example: Change SphereCap to SphereHandleCap.")] - #pragma warning disable 618 +#pragma warning disable 618 public static float DoCenter(int id, float value, Vector3 position, Quaternion rotation, float size, Handles.DrawCapFunction capFunc, float snap) - #pragma warning restore 618 +#pragma warning restore 618 { Event evt = Event.current; switch (evt.GetTypeForControl(id)) @@ -105,6 +111,7 @@ public static float DoCenter(int id, float value, Vector3 position, Quaternion r case EventType.Layout: HandleUtility.AddControl(id, HandleUtility.DistanceToCircle(position, size * .15f)); break; + case EventType.MouseDown: // am I closest to the thingy? if (HandleUtility.nearestControl == id && evt.button == 0) @@ -116,6 +123,7 @@ public static float DoCenter(int id, float value, Vector3 position, Quaternion r EditorGUIUtility.SetWantsMouseJumping(1); } break; + case EventType.MouseDrag: if (GUIUtility.hotControl == id) { @@ -126,10 +134,12 @@ public static float DoCenter(int id, float value, Vector3 position, Quaternion r evt.Use(); } break; + case EventType.MouseMove: if (id == HandleUtility.nearestControl) HandleUtility.Repaint(); break; + case EventType.KeyDown: if (GUIUtility.hotControl == id) { @@ -141,6 +151,7 @@ public static float DoCenter(int id, float value, Vector3 position, Quaternion r } } break; + case EventType.MouseUp: if (GUIUtility.hotControl == id && (evt.button == 0 || evt.button == 2)) { @@ -150,6 +161,7 @@ public static float DoCenter(int id, float value, Vector3 position, Quaternion r EditorGUIUtility.SetWantsMouseJumping(0); } break; + case EventType.Repaint: Color temp = Color.white; if (id == GUIUtility.hotControl) @@ -180,6 +192,7 @@ public static float DoCenter(int id, float value, Vector3 position, Quaternion r case EventType.Layout: capFunction(id, position, rotation, size * .15f, EventType.Layout); break; + case EventType.MouseDown: // am I closest to the thingy? if (HandleUtility.nearestControl == id && evt.button == 0 && !evt.alt) @@ -192,6 +205,7 @@ public static float DoCenter(int id, float value, Vector3 position, Quaternion r EditorGUIUtility.SetWantsMouseJumping(1); } break; + case EventType.MouseDrag: if (GUIUtility.hotControl == id) { @@ -202,6 +216,7 @@ public static float DoCenter(int id, float value, Vector3 position, Quaternion r evt.Use(); } break; + case EventType.KeyDown: if (GUIUtility.hotControl == id) { @@ -213,6 +228,7 @@ public static float DoCenter(int id, float value, Vector3 position, Quaternion r } } break; + case EventType.MouseUp: if (GUIUtility.hotControl == id && (evt.button == 0 || evt.button == 2)) { @@ -223,10 +239,12 @@ public static float DoCenter(int id, float value, Vector3 position, Quaternion r EditorGUIUtility.SetWantsMouseJumping(0); } break; + case EventType.MouseMove: if (id == HandleUtility.nearestControl) HandleUtility.Repaint(); break; + case EventType.Repaint: Color temp = Color.white; if (id == GUIUtility.hotControl) diff --git a/Editor/Mono/EditorMode/ModeService.cs b/Editor/Mono/EditorMode/ModeService.cs index 3d502f56b5..57e3403229 100644 --- a/Editor/Mono/EditorMode/ModeService.cs +++ b/Editor/Mono/EditorMode/ModeService.cs @@ -7,10 +7,11 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using UnityEditor.ShortcutManagement; +using Unity.MPE; using UnityEngine; using UnityEngine.Internal; using UnityEngine.UIElements; +using UnityEditor.ShortcutManagement; using JSONObject = System.Collections.IDictionary; @@ -46,7 +47,6 @@ public struct ModeChangedArgs internal const string k_DefaultModeId = "default"; internal const string k_ModeIndexKeyName = "mode-index"; - internal const string k_ModeLayoutKeyName = "mode-layout"; internal const string k_CapabilitiesSectionName = "capabilities"; internal const string k_ExecuteHandlersSectionName = "execute_handlers"; internal const string k_LayoutsSectionName = "layouts"; @@ -330,7 +330,12 @@ private static void SaveProjectPrefModeIndex(int modeIndex) private static string GetProjectPrefKeyName(string prefix) { - return $"{prefix}-{Application.productName}"; + var key = $"{prefix}-{Application.productName}"; + if (!string.IsNullOrEmpty(ProcessService.roleName)) + { + key += "-" + ProcessService.roleName; + } + return key; } private static void UpdateModeMenus(int modeIndex) @@ -460,7 +465,7 @@ private static void OnModeChangeLayouts(ModeChangedArgs args) try { // Load the last valid layout for this mode - WindowLayout.LoadDefaultWindowPreferences(); + WindowLayout.LoadDefaultWindowPreferencesEx(true); } catch (Exception) { diff --git a/Editor/Mono/EditorResources.cs b/Editor/Mono/EditorResources.cs index 3b68f12159..2cbf887e95 100644 --- a/Editor/Mono/EditorResources.cs +++ b/Editor/Mono/EditorResources.cs @@ -6,25 +6,29 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using JetBrains.Annotations; using UnityEditor.StyleSheets; -using UnityEditorInternal; using UnityEngine; using UnityEngine.Internal; +using UnityEngine.Scripting; namespace UnityEditor.Experimental { [ExcludeFromDocs] public partial class EditorResources { - // Global editor styles - internal static StyleCatalog styleCatalog { get; private set; } + private static StyleCatalog s_StyleCatalog; + private static Dictionary s_BuiltInFonts = null; - static EditorResources() + // Global editor styles + internal static StyleCatalog styleCatalog { - styleCatalog = new StyleCatalog(); - - if (CanEnableExtendedStyles()) - GUIStyle.onDraw = StylePainter.DrawStyle; + get + { + if (s_StyleCatalog == null) + BuildCatalog(); + return s_StyleCatalog; + } } private static bool CanEnableExtendedStyles() @@ -53,7 +57,101 @@ internal static string GetDefaultFont() internal static string GetCurrentFont() { - return EditorPrefs.GetString("user_editor_font", GetDefaultFont()); + var currentFont = EditorPrefs.GetString("user_editor_font", GetDefaultFont()); + + // If the current is not available then fallback to the default font + if (!GetSupportedFonts().Contains(currentFont)) + { + currentFont = GetDefaultFont(); + EditorPrefs.DeleteKey("user_editor_font"); + } + + return currentFont; + } + + private static Font s_SmallFont; + internal static Font GetSmallFont() + { + if (s_SmallFont == null) + { + var currentFont = GetCurrentFont(); + + if (IsSystemFont(currentFont)) + { + s_SmallFont = EditorGUIUtility.LoadRequired("Fonts/System/System Small.ttf") as Font; + s_SmallFont.fontNames = new[] { currentFont }; + } + else + { + if (currentFont == "Roboto") + { + s_SmallFont = EditorGUIUtility.LoadRequired("Fonts/roboto/Roboto-Small.ttf") as Font; + } + else if (currentFont == "Lucida Grande") + { + s_SmallFont = EditorGUIUtility.LoadRequired("Fonts/Lucida Grande small.ttf") as Font; + } + else + { + s_SmallFont = GetNormalFont(); + } + } + } + + return s_SmallFont; + } + + private static Font s_NormalFont; + internal static Font GetNormalFont() + { + if (s_NormalFont == null) + { + var currentFont = GetCurrentFont(); + + if (IsSystemFont(currentFont)) + { + s_NormalFont = EditorGUIUtility.LoadRequired("Fonts/System/System Normal.ttf") as Font; + s_NormalFont.fontNames = new[] { currentFont }; + } + else + { + s_NormalFont = EditorGUIUtility.LoadRequired(builtInFonts[currentFont]) as Font; + } + } + + return s_NormalFont; + } + + private static Font s_BoldFont; + internal static Font GetBoldFont() + { + if (s_BoldFont == null) + { + var currentFont = GetCurrentFont(); + + if (IsSystemFont(currentFont)) + { + s_BoldFont = EditorGUIUtility.LoadRequired("Fonts/System/System Normal Bold.ttf") as Font; + s_BoldFont.fontNames = new[] { currentFont + " Bold" }; + } + else + { + if (currentFont == "Roboto") + { + s_BoldFont = EditorGUIUtility.LoadRequired("Fonts/roboto/Roboto-Bold.ttf") as Font; + } + else if (currentFont == "Lucida Grande") + { + s_BoldFont = EditorGUIUtility.LoadRequired("Fonts/Lucida Grande Bold.ttf") as Font; + } + else + { + s_BoldFont = EditorGUIUtility.LoadRequired(builtInFonts[currentFont]) as Font; + } + } + } + + return s_BoldFont; } private static List s_SupportedFonts = null; @@ -74,27 +172,25 @@ internal static List GetSupportedFonts() s_SupportedFonts.Add(builtinFont); } - s_SupportedFonts.Add(EditorResources.GetDefaultFont()); + if (!s_SupportedFonts.Contains(EditorResources.GetDefaultFont())) + s_SupportedFonts.Add(EditorResources.GetDefaultFont()); } return s_SupportedFonts; } - private static Dictionary s_BuiltInFonts = null; - internal static Dictionary builtInFonts { get { if (s_BuiltInFonts == null) { - s_BuiltInFonts = new Dictionary(); - - if (Application.platform == RuntimePlatform.WindowsEditor) + s_BuiltInFonts = new Dictionary { - s_BuiltInFonts["Roboto"] = "Fonts/roboto/Roboto-Regular.ttf"; - } - else + ["Roboto"] = "Fonts/roboto/Roboto-Regular.ttf" + }; + + if (Application.platform != RuntimePlatform.WindowsEditor) { s_BuiltInFonts["Lucida Grande"] = "Fonts/Lucida Grande.ttf"; } @@ -133,25 +229,33 @@ private static List GetDefaultStyleCatalogPaths() return catalogFiles; } + [UsedImplicitly, RequiredByNativeCode] internal static void BuildCatalog() { - styleCatalog = new StyleCatalog(); + s_StyleCatalog = new StyleCatalog(); var paths = GetDefaultStyleCatalogPaths(); foreach (var editorUssPath in AssetDatabase.FindAssets("t:StyleSheet").Select(AssetDatabase.GUIDToAssetPath).Where(IsEditorStyleSheet)) paths.Add(editorUssPath); styleCatalog.Load(paths); - if (CanEnableExtendedStyles()) + } + + internal static void RefreshSkin() + { + if (!CanEnableExtendedStyles()) + return; + + GUIStyle.onDraw = StylePainter.DrawStyle; + + // Update gui skin style layouts + var skin = GUIUtility.GetDefaultSkin(); + if (skin != null) { - // Update gui skin style layouts - var skin = GUIUtility.GetDefaultSkin(); - if (skin != null) - { - // TODO: Emit OnStyleCatalogLoaded - if (Path.GetFileName(Path.GetDirectoryName(Application.dataPath)) == "editor_resources") - ConverterUtils.ResetSkinToPristine(skin, EditorGUIUtility.isProSkin ? SkinTarget.Dark : SkinTarget.Light); - UpdateGUIStyleProperties(skin); - } + // TODO: Emit OnStyleCatalogLoaded + if (Path.GetFileName(Path.GetDirectoryName(Application.dataPath)) == "editor_resources") + ConverterUtils.ResetSkinToPristine(skin, EditorGUIUtility.isProSkin ? SkinTarget.Dark : SkinTarget.Light); + skin.font = GetNormalFont(); + UpdateGUIStyleProperties(skin); } } @@ -209,34 +313,6 @@ internal static void SwitchTheme() private static void UpdateGUIStyleProperties(string name, GUIStyle style) { - if (LocalizationDatabase.currentEditorLanguage == SystemLanguage.English) - { - var rootBlock = styleCatalog.GetStyle(StyleCatalogKeyword.root, StyleState.root); - var systemSmallFont = EditorGUIUtility.LoadRequired("Fonts/System/System Small.ttf") as Font; - var systemNormalFont = EditorGUIUtility.LoadRequired("Fonts/System/System Normal.ttf") as Font; - var currentFont = GetCurrentFont(); - - if (IsSystemFont(currentFont)) - { - var defaultSmallFontSize = rootBlock.GetInt("--unity-font-size-small", 11); - var systemFont = style.fontSize == defaultSmallFontSize ? systemSmallFont : systemNormalFont; - systemFont.fontNames = new[] { currentFont }; - style.font = systemFont; - } - else - { - if ((currentFont == "Roboto") && (style.fontStyle == FontStyle.Bold)) - { - style.font = EditorGUIUtility.LoadRequired("Fonts/roboto/Roboto-Medium.ttf") as Font; - style.fontStyle = FontStyle.Normal; - } - else - { - style.font = EditorGUIUtility.LoadRequired(builtInFonts[currentFont]) as Font; - } - } - } - var sname = GUIStyleExtensions.StyleNameToBlockName(style.name, false); var block = styleCatalog.GetStyle(sname); if (!block.IsValid()) diff --git a/Editor/Mono/EditorSettings.bindings.cs b/Editor/Mono/EditorSettings.bindings.cs index 792ed22734..abf2395a5a 100644 --- a/Editor/Mono/EditorSettings.bindings.cs +++ b/Editor/Mono/EditorSettings.bindings.cs @@ -5,6 +5,7 @@ using System; using System.Linq; using System.Runtime.InteropServices; +using UnityEditor.VisualStudioIntegration; using UnityEngine.Bindings; using Object = UnityEngine.Object; @@ -200,7 +201,7 @@ public static string[] projectGenerationUserExtensions public static string[] projectGenerationBuiltinExtensions { - get { return new[] { "cs", "uxml", "uss", "shader", "compute", "cginc", "hlsl", "glslinc", "template" }; } + get { return SolutionSynchronizer.BuiltinSupportedExtensions.Keys.ToArray(); } } internal static extern string Internal_ProjectGenerationUserExtensions @@ -228,6 +229,9 @@ internal static extern string Internal_ProjectGenerationUserExtensions [StaticAccessor("GetEditorSettings()", StaticAccessorType.Dot)] internal static extern void SetEtcTextureCompressorDefaultBehavior(); + [StaticAccessor("GetEditorSettings()", StaticAccessorType.Dot)] + public static extern bool useLegacyProbeSampleCount { get; set; } + [StaticAccessor("GetEditorSettings()", StaticAccessorType.Dot)] public static extern bool enterPlayModeOptionsEnabled { get; set; } diff --git a/Editor/Mono/EditorUserBuildSettings.bindings.cs b/Editor/Mono/EditorUserBuildSettings.bindings.cs index a46b2e3de4..334e63a8fd 100644 --- a/Editor/Mono/EditorUserBuildSettings.bindings.cs +++ b/Editor/Mono/EditorUserBuildSettings.bindings.cs @@ -273,17 +273,6 @@ public static extern BuildTarget selectedStandaloneTarget set; } - internal static extern BuildTarget selectedFacebookTarget - { - [NativeMethod("GetSelectedFacebookTarget")] - get; - [NativeMethod("SetSelectedFacebookTargetFromBindings")] - set; - } - - internal static extern string facebookAccessToken { get; set; } - - ///PS4 Build Subtarget public static extern PS4BuildSubtarget ps4BuildSubtarget { @@ -575,6 +564,9 @@ public static bool webGLUsePreBuiltUnityEngine // Start the player with a connection to the profiler. public static extern bool connectProfiler { get; set; } + // Build the player with deep profiler support. + public static extern bool buildWithDeepProfilingSupport { get; set; } + // Enable source-level debuggers to connect. public static extern bool allowDebugging { get; set; } diff --git a/Editor/Mono/EditorUserBuildSettingsUtils.cs b/Editor/Mono/EditorUserBuildSettingsUtils.cs index 5226c39902..5a3d3f30b7 100644 --- a/Editor/Mono/EditorUserBuildSettingsUtils.cs +++ b/Editor/Mono/EditorUserBuildSettingsUtils.cs @@ -15,8 +15,6 @@ public static BuildTarget CalculateSelectedBuildTarget() { case BuildTargetGroup.Standalone: return DesktopStandaloneBuildWindowExtension.GetBestStandaloneTarget(EditorUserBuildSettings.selectedStandaloneTarget); - case BuildTargetGroup.Facebook: - return EditorUserBuildSettings.selectedFacebookTarget; default: if (BuildPlatforms.instance == null) throw new System.Exception("Build platforms are not initialized."); diff --git a/Editor/Mono/EditorUserSettings.bindings.cs b/Editor/Mono/EditorUserSettings.bindings.cs index cc94a79eb7..6ab4b47acb 100644 --- a/Editor/Mono/EditorUserSettings.bindings.cs +++ b/Editor/Mono/EditorUserSettings.bindings.cs @@ -49,6 +49,9 @@ public static string GetConfigValue(string name) [NativeProperty("VCOverwriteFailedCheckoutAssets")] public static extern bool overwriteFailedCheckoutAssets { get; set; } + [NativeProperty("VCOverlayIcons")] + public static extern bool overlayIcons { get; set; } + [NativeProperty("VCAllowAsyncUpdate")] public static extern bool allowAsyncStatusUpdate { get; set; } diff --git a/Editor/Mono/EditorUtility.cs b/Editor/Mono/EditorUtility.cs index bea5fcb9e9..f82636db65 100644 --- a/Editor/Mono/EditorUtility.cs +++ b/Editor/Mono/EditorUtility.cs @@ -7,6 +7,7 @@ using UnityEditor.Experimental; using UnityEditor.SceneManagement; using UnityEngine; +using UnityEngine.Internal; using Object = UnityEngine.Object; namespace UnityEditor @@ -35,6 +36,12 @@ public enum TextureCompressionQuality Best = 100 // Best compression } + public enum DialogOptOutDecisionType + { + ForThisMachine, + ForThisSession, + } + public class SceneAsset : Object { private SceneAsset() {} @@ -42,6 +49,25 @@ private SceneAsset() {} public partial class EditorUtility { + static class Content + { + public static readonly string Cancel = L10n.Tr("Cancel"); + static readonly string k_DialogOptOutForThisMachine = L10n.Tr("Do not show me this message again on this machine."); + static readonly string k_DialogOptOutForThisSession = L10n.Tr("Do not show me this message again for this session."); + public static string GetDialogOptOutMessage(DialogOptOutDecisionType dialogOptOutType) + { + switch (dialogOptOutType) + { + case DialogOptOutDecisionType.ForThisMachine: + return k_DialogOptOutForThisMachine; + case DialogOptOutDecisionType.ForThisSession: + return k_DialogOptOutForThisSession; + default: + throw new NotImplementedException(string.Format("The DialogOptOut type named {0} has not been implemented.", dialogOptOutType)); + } + } + } + public delegate void SelectMenuItemFunction(object userData, string[] options, int selected); public static bool LoadWindowLayout(string path) @@ -155,6 +181,70 @@ public static bool BuildResourceFile(Object[] selection, string pathName) return false; } + public static bool GetDialogOptOutDecision(DialogOptOutDecisionType dialogOptOutDecisionType, string dialogOptOutDecisionStorageKey) + { + switch (dialogOptOutDecisionType) + { + case DialogOptOutDecisionType.ForThisMachine: + return EditorPrefs.GetBool(dialogOptOutDecisionStorageKey, false); + case DialogOptOutDecisionType.ForThisSession: + return SessionState.GetBool(dialogOptOutDecisionStorageKey, false); + default: + throw new NotImplementedException(string.Format("The DialogOptOut type named {0} has not been implemented.", dialogOptOutDecisionType)); + } + } + + public static void SetDialogOptOutDecision(DialogOptOutDecisionType dialogOptOutDecisionType, string dialogOptOutDecisionStorageKey, bool optOutDecision) + { + switch (dialogOptOutDecisionType) + { + case DialogOptOutDecisionType.ForThisMachine: + EditorPrefs.SetBool(dialogOptOutDecisionStorageKey, optOutDecision); + break; + case DialogOptOutDecisionType.ForThisSession: + SessionState.SetBool(dialogOptOutDecisionStorageKey, optOutDecision); + break; + default: + throw new NotImplementedException(string.Format("The DialogOptOut type named {0} has not been implemented.", dialogOptOutDecisionType)); + } + } + + public static bool DisplayDialog(string title, string message, string ok, DialogOptOutDecisionType dialogOptOutDecisionType, string dialogOptOutDecisionStorageKey) + { + return DisplayDialog(title, message, ok, string.Empty, dialogOptOutDecisionType, dialogOptOutDecisionStorageKey); + } + + public static bool DisplayDialog(string title, string message, string ok, [DefaultValue("\"\"")] string cancel, DialogOptOutDecisionType dialogOptOutDecisionType, string dialogOptOutDecisionStorageKey) + { + if (GetDialogOptOutDecision(dialogOptOutDecisionType, dialogOptOutDecisionStorageKey)) + { + return true; + } + else + { + bool optOutDecision; + bool dialogDecision = DisplayDialog(title, message, ok, cancel, Content.GetDialogOptOutMessage(dialogOptOutDecisionType), out optOutDecision); + // Cancel means the user pressed ESC as the Cancel button was grayed out. Don't store the opt-out decision on cancel. Also, only store it if the user opted out since it defaults to opt-in. + if (dialogDecision && optOutDecision) + SetDialogOptOutDecision(dialogOptOutDecisionType, dialogOptOutDecisionStorageKey, optOutDecision); + return dialogDecision; + } + } + + // TODO: This is an MVP solution. The OptOut option should be a check-box in the dialog. To achieve that, this API will need to move to bindings and get platform specific implementations. + static bool DisplayDialog(string title, string message, string ok, string cancel, string optOutText, out bool optOutDecision) + { + if (string.IsNullOrEmpty(cancel)) + { + // we can't allow empty cancel buttons in this MVP workaround. Only the two button dialog would be possible to use and it can't differentiate between pressing a cancel button (labeled with OptOut text) and pressing X or ESC. + cancel = Content.Cancel; + } + int result = DisplayDialogComplex(title, message, ok, cancel, string.Format("{0} - {1}", ok, optOutText)); + // result 0 -> OK, 1 -> Cancel, 2 -> Ok & opt out + optOutDecision = result == 2; + return result != 1; + } + public static void DisplayPopupMenu(Rect position, string menuItemPath, MenuCommand command) { // Validate input. Fixes case 406024: 'Custom context menu in a custom window crashes Unity' diff --git a/Editor/Mono/EditorWindow.cs b/Editor/Mono/EditorWindow.cs index a3f748e6d2..24fd80f193 100644 --- a/Editor/Mono/EditorWindow.cs +++ b/Editor/Mono/EditorWindow.cs @@ -793,6 +793,12 @@ public static T CreateWindow(string title, params System.Type[] desiredDockNe return win; } + public static bool HasOpenInstances() where T : UnityEditor.EditorWindow + { + UnityEngine.Object[] wins = Resources.FindObjectsOfTypeAll(typeof(T)); + return wins != null && wins.Length > 0; + } + // Focuses the first found EditorWindow of specified type if it is open. public static void FocusWindowIfItsOpen(System.Type t) { diff --git a/Editor/Mono/GI/LightmapEditorSettings.bindings.cs b/Editor/Mono/GI/LightmapEditorSettings.bindings.cs index ac24ef301c..2e07e464cb 100644 --- a/Editor/Mono/GI/LightmapEditorSettings.bindings.cs +++ b/Editor/Mono/GI/LightmapEditorSettings.bindings.cs @@ -69,7 +69,10 @@ public enum DenoiserType Optix = 1, // The Intel Open Image AI denoiser is applied. - OpenImage = 2 + OpenImage = 2, + + // The AMD Radeon Pro Image Processing denoiser is applied. + RadeonPro = 3 } // Which path tracer filter is used. @@ -200,6 +203,11 @@ public enum FilterType [NativeName("PVREnvironmentSampleCount")] public extern static int environmentSampleCount { get; set; } + // How many samples to use for light probes relative to lightmap texels + [StaticAccessor("GetLightmapEditorSettings()")] + [NativeName("LightProbeSampleCountMultiplier")] + public extern static float lightProbeSampleCountMultiplier { get; set; } + // How many reference points to generate when using MIS [StaticAccessor("GetLightmapEditorSettings()")] [NativeName("PVREnvironmentReferencePointCount")] @@ -216,6 +224,10 @@ public enum FilterType [NativeHeader("Editor/Src/GI/EditorHelpers.h")] extern static internal bool IsOptixDenoiserSupported(); + [FreeFunction] + [NativeHeader("Editor/Src/GI/EditorHelpers.h")] + extern static internal bool IsRadeonDenoiserSupported(); + [FreeFunction] [NativeHeader("Editor/Src/GI/EditorHelpers.h")] extern static internal bool IsOpenImageDenoiserSupported(); diff --git a/Editor/Mono/GI/Lightmapping.bindings.cs b/Editor/Mono/GI/Lightmapping.bindings.cs index 0dccdbfa9a..12c99ed888 100644 --- a/Editor/Mono/GI/Lightmapping.bindings.cs +++ b/Editor/Mono/GI/Lightmapping.bindings.cs @@ -285,7 +285,7 @@ internal static void Internal_CallStartedRenderingFunctions() startedRendering(); } - internal static event Action lightingDataUpdated; + public static event Action lightingDataUpdated; internal static void Internal_CallLightingDataUpdatedFunctions() { diff --git a/Editor/Mono/GUI/AboutWindow.cs b/Editor/Mono/GUI/AboutWindow.cs index 53a6fd9a59..945f7962c9 100644 --- a/Editor/Mono/GUI/AboutWindow.cs +++ b/Editor/Mono/GUI/AboutWindow.cs @@ -4,6 +4,10 @@ using UnityEngine; using System; +using System.Collections; +using System.Collections.Generic; +using UnityEditor; +using UnityEditor.VisualStudioIntegration; using UnityEditorInternal; namespace UnityEditor @@ -146,6 +150,9 @@ public void OnGUI() GUILayout.BeginVertical(); GUILayout.FlexibleSpace(); + var VSTUlabel = UnityVSSupport.GetAboutWindowLabel(); + if (VSTUlabel.Length > 0) + GUILayout.Label(VSTUlabel, "MiniLabel"); GUILayout.Label(InternalEditorUtility.GetUnityCopyright(), "MiniLabel"); GUILayout.EndVertical(); GUILayout.Space(10); diff --git a/Editor/Mono/GUI/AboutWindowNames.cs b/Editor/Mono/GUI/AboutWindowNames.cs index f2569ffd6f..0fb24ec4f0 100644 --- a/Editor/Mono/GUI/AboutWindowNames.cs +++ b/Editor/Mono/GUI/AboutWindowNames.cs @@ -9,7 +9,6 @@ using System.Linq; using System.Reflection; using System.Text; -using UnityEditor; namespace UnityEditor { @@ -38,7 +37,6 @@ public class CreditEntry public string region; public string twitter; public string nationality; - public string gravatar_hash; public bool alumni; public string FormattedName diff --git a/Editor/Mono/GUI/ColorPicker.cs b/Editor/Mono/GUI/ColorPicker.cs index 5d56f58d4d..98f0afe1bc 100644 --- a/Editor/Mono/GUI/ColorPicker.cs +++ b/Editor/Mono/GUI/ColorPicker.cs @@ -411,9 +411,10 @@ static void HSVToRGBArray(Color[] colors, bool convertToGamma) public static Texture2D MakeTexture(int width, int height) { - Texture2D tex = new Texture2D(width, height, TextureFormat.RGBA32, false, true); - tex.hideFlags = HideFlags.HideAndDontSave; - tex.wrapMode = TextureWrapMode.Clamp; + Texture2D tex = new Texture2D(width, height, TextureFormat.RGBA32, false, true) + { + hideFlags = HideFlags.HideAndDontSave, wrapMode = TextureWrapMode.Clamp + }; return tex; } @@ -454,7 +455,7 @@ void DrawColorSpaceBox(Rect colorBoxRect, float constantValue) static class Styles { public const float fixedWindowWidth = 233; - public const float hexFieldWidth = 72f; + public const float hexFieldWidth = 85f; public const float sliderModeFieldWidth = hexFieldWidth; public const float channelSliderLabelWidth = 14f; public const float sliderTextFieldWidth = 45f; @@ -475,7 +476,6 @@ static class Styles public static readonly GUIStyle hueDialBackgroundHDR = "ColorPickerHueRing HDR"; public static readonly GUIStyle hueDialThumb = "ColorPickerHueRingThumb"; public static readonly GUIStyle sliderBackground = "ColorPickerSliderBackground"; - public static readonly GUIStyle sliderThumb = "ColorPickerHorizThumb"; public static readonly GUIStyle background = "ColorPickerBackground"; public static readonly GUIStyle exposureSwatch = "ColorPickerExposureSwatch"; public static readonly GUIStyle selectedExposureSwatchStroke = "ColorPickerCurrentExposureSwatchBorder"; @@ -536,14 +536,16 @@ void InitializePresetsLibraryIfNeeded() if (m_ColorLibraryEditor == null) { var saveLoadHelper = new ScriptableObjectSaveLoadHelper("colors", SaveType.Text); - m_ColorLibraryEditor = new PresetLibraryEditor(saveLoadHelper, m_ColorLibraryEditorState, OnClickedPresetSwatch); - m_ColorLibraryEditor.previewAspect = 1f; - m_ColorLibraryEditor.minMaxPreviewHeight = new Vector2(ColorPresetLibrary.kSwatchSize, ColorPresetLibrary.kSwatchSize); - m_ColorLibraryEditor.settingsMenuRightMargin = 2f; - m_ColorLibraryEditor.useOnePixelOverlappedGrid = true; - m_ColorLibraryEditor.alwaysShowScrollAreaHorizontalLines = false; - m_ColorLibraryEditor.marginsForGrid = new RectOffset(0, 0, 2, 2); - m_ColorLibraryEditor.marginsForList = new RectOffset(0, 5, 2, 2); + m_ColorLibraryEditor = new PresetLibraryEditor(saveLoadHelper, m_ColorLibraryEditorState, OnClickedPresetSwatch) + { + previewAspect = 1f, + minMaxPreviewHeight = new Vector2(ColorPresetLibrary.kSwatchSize, ColorPresetLibrary.kSwatchSize), + settingsMenuRightMargin = 2f, + useOnePixelOverlappedGrid = true, + alwaysShowScrollAreaHorizontalLines = false, + marginsForGrid = new RectOffset(0, 0, 2, 2), + marginsForList = new RectOffset(0, 5, 2, 2) + }; m_ColorLibraryEditor.InitializeGrid(Styles.fixedWindowWidth - (Styles.background.padding.left + Styles.background.padding.right)); } } @@ -570,7 +572,16 @@ void DoColorSwatchAndEyedropper() var oldGUIColor = GUI.color; GUI.color = Color.white; - if (GUILayout.Button(Styles.eyeDropper, GUIStyle.none, GUILayout.Width(40), GUILayout.ExpandWidth(false))) + Event evt = Event.current; + Rect position = GUILayoutUtility.GetRect(Styles.eyeDropper, GUIStyle.none, GUILayout.Width(40), GUILayout.ExpandWidth(false)); + bool startEyeDropper = false; + if (evt.type == EventType.Repaint || !evt.isDirectManipulationDevice) + startEyeDropper = GUI.Button(position, Styles.eyeDropper, GUIStyle.none); + // For a direct manipulation device, the color picking is on a drag&drop, so we just need to start the eyeDropper on mouseDown instead of mouseUp + else if (evt.type == EventType.MouseDown && position.Contains(evt.mousePosition)) + startEyeDropper = true; + + if (startEyeDropper) { GUIUtility.keyboardControl = 0; EyeDropper.Start(m_Parent); @@ -578,7 +589,6 @@ void DoColorSwatchAndEyedropper() GUIUtility.ExitGUI(); } - var swatchColor = m_Color.exposureAdjustedColor; // current swatch and original swatch have the same size, so they can lay out in the same row var rect = GUILayoutUtility.GetRect(Styles.currentColorSwatchFill, Styles.currentColorSwatch, GUILayout.ExpandWidth(true)); @@ -594,7 +604,7 @@ void DoColorSwatchAndEyedropper() var contentColor = GUI.contentColor; var id = GUIUtility.GetControlID(FocusType.Passive); - if (Event.current.type == EventType.Repaint) + if (evt.type == EventType.Repaint) { GUI.backgroundColor = m_Color.exposureAdjustedColor.a == 1f ? Color.clear : Color.white; GUI.contentColor = GetGUIColor(m_Color.exposureAdjustedColor); @@ -607,7 +617,7 @@ void DoColorSwatchAndEyedropper() if (GUI.Button(swatchRect, Styles.originalColorSwatchFill, Styles.originalColorSwatch)) { m_Color.Reset(); - Event.current.Use(); + evt.Use(); OnColorChanged(); } @@ -1060,9 +1070,7 @@ public static Texture2D GetGradientTextureWithAlpha0To1() static Texture2D CreateGradientTexture(string name, int width, int height, Color leftColor, Color rightColor) { - var texture = new Texture2D(width, height, TextureFormat.RGBA32, false, true); - texture.name = name; - texture.hideFlags = HideFlags.HideAndDontSave; + var texture = new Texture2D(width, height, TextureFormat.RGBA32, false, true) {name = name, hideFlags = HideFlags.HideAndDontSave}; var pixels = new Color[width * height]; for (int i = 0; i < width; i++) @@ -1140,6 +1148,11 @@ static void Show(GUIView viewToUpdate, Action colorChangedCallback, Color cp.m_IsOSColorPicker = false; cp.m_SliderMode = (SliderMode)EditorPrefs.GetInt(k_SliderModeHDRPrefKey, (int)SliderMode.RGB); } + else + { + // If it is not an HDR value we set the exposure back to 0. + cp.m_Color.exposureValue = 0; + } if (cp.m_IsOSColorPicker) { @@ -1275,7 +1288,7 @@ static void Start(GUIView viewToUpdate, Action colorPickedCallback) instance.AddToAuxWindowList(); win.SetInvisible(); instance.SetMinMaxSizes(new Vector2(0, 0), new Vector2(kDummyWindowSize, kDummyWindowSize)); - win.position = new Rect(-kDummyWindowSize / 2, -kDummyWindowSize / 2, kDummyWindowSize, kDummyWindowSize); + win.position = new Rect(-kDummyWindowSize / 2f, -kDummyWindowSize / 2f, kDummyWindowSize, kDummyWindowSize); instance.wantsMouseMove = true; instance.StealMouseCapture(); } @@ -1337,7 +1350,7 @@ public static void DrawPreview(Rect position) } Vector2 p = GUIUtility.GUIToScreenPoint(Event.current.mousePosition); - Vector2 mPos = p - new Vector2((width / 2), (height / 2)); + Vector2 mPos = p - new Vector2((width / 2f), (height / 2f)); preview.SetPixels(InternalEditorUtility.ReadScreenPixelUnderCursor(p, width, height), 0); preview.Apply(true); @@ -1370,40 +1383,74 @@ protected override void OldOnGUI() // On mouse move/click we remember screen coordinates where we are. Then we'll use that // in GetPickedColor to read. The reason is that because GetPickedColor might be called from // an event which is different, so the coordinates would be already wrong. - switch (Event.current.type) + // for direct manipulation devices, it is on mouse drag/up + if (Event.current.isDirectManipulationDevice) { - case EventType.MouseMove: - s_PickCoordinates = GUIUtility.GUIToScreenPoint(Event.current.mousePosition); + switch (Event.current.type) + { + case EventType.MouseDrag: + UpdateEyeDropper(); + break; + case EventType.MouseUp: + StopEyeDropper(); + break; + case EventType.KeyDown: + CancelEyeDropper(); + break; + } + } + else + { + switch (Event.current.type) + { + case EventType.MouseMove: + UpdateEyeDropper(); + break; + case EventType.MouseDown: + StopEyeDropper(); + break; + case EventType.KeyDown: + CancelEyeDropper(); + break; + } + } + } - StealMouseCapture(); - SendEvent(EventCommandNames.EyeDropperUpdate, true, false); - break; - case EventType.MouseDown: - if (Event.current.button == 0) - { - s_PickCoordinates = GUIUtility.GUIToScreenPoint(Event.current.mousePosition); + private void UpdateEyeDropper() + { + s_PickCoordinates = GUIUtility.GUIToScreenPoint(Event.current.mousePosition); - // We have to close helper window before we read color from screen. On Win - // the window covers whole desktop (see Show()) and is black with 0x01 alpha value. - // That might cause invalid picked color. - window.Close(); - s_LastPickedColor = GetPickedColor(); - Event.current.Use(); - SendEvent(EventCommandNames.EyeDropperClicked, true); - if (m_ColorPickedCallback != null) - { - m_ColorPickedCallback(s_LastPickedColor); - } - } - break; - case EventType.KeyDown: - if (Event.current.keyCode == KeyCode.Escape) - { - window.Close(); - Event.current.Use(); - SendEvent(EventCommandNames.EyeDropperCancelled, true); - } - break; + StealMouseCapture(); + SendEvent(EventCommandNames.EyeDropperUpdate, true, false); + } + + private void StopEyeDropper() + { + if (Event.current.button == 0) + { + s_PickCoordinates = GUIUtility.GUIToScreenPoint(Event.current.mousePosition); + + // We have to close helper window before we read color from screen. On Win + // the window covers whole desktop (see Show()) and is black with 0x01 alpha value. + // That might cause invalid picked color. + window.Close(); + s_LastPickedColor = GetPickedColor(); + Event.current.Use(); + SendEvent(EventCommandNames.EyeDropperClicked, true); + if (m_ColorPickedCallback != null) + { + m_ColorPickedCallback(s_LastPickedColor); + } + } + } + + private void CancelEyeDropper() + { + if (Event.current.keyCode == KeyCode.Escape) + { + window.Close(); + Event.current.Use(); + SendEvent(EventCommandNames.EyeDropperCancelled, true); } } diff --git a/Editor/Mono/GUI/DockArea.cs b/Editor/Mono/GUI/DockArea.cs index 7c4fb79264..72a555071b 100644 --- a/Editor/Mono/GUI/DockArea.cs +++ b/Editor/Mono/GUI/DockArea.cs @@ -328,7 +328,6 @@ protected override void OldOnGUI() return; var borderSize = GetBorderSize(); - HandleSplitView(); background = "dockarea"; @@ -340,8 +339,6 @@ protected override void OldOnGUI() DrawDockAreaBackground(dockAreaRect); - // FixDockAreaRectBorders(customBorder, ref dockAreaRect); - var viewRect = UpdateViewRect(dockAreaRect); var titleBarRect = new Rect(viewRect.x, dockAreaRect.y, viewRect.width, borderSize.top); var tabAreaRect = new Rect(titleBarRect.x, viewRect.y - kTabHeight, titleBarRect.width - GetExtraButtonsWidth(), kTabHeight); @@ -362,35 +359,12 @@ protected override void OldOnGUI() DrawView(viewRect, dockAreaRect); DrawTabScrollers(tabAreaRect); + HandleSplitView(); EditorGUI.ShowRepaints(); Highlighter.ControlHighlightGUI(this); } - private float GetViewMarginTopOffset(bool isBottomTab, bool customBorder) - { - float viewMarginTopOffset = 3f; - if (isBottomTab) - viewMarginTopOffset = 2f; - if (customBorder) - viewMarginTopOffset = 0f; - return viewMarginTopOffset; - } - - internal void UpdateDockAreaFromLocation(Rect windowPosition, Rect containerPosition, ref Rect dockAreaRect) - { - float sideBorder = kSideBorders; - if (windowPosition.x == 0) - { - dockAreaRect.x -= sideBorder; - dockAreaRect.width += sideBorder; - } - if (windowPosition.xMax == containerPosition.width) - { - dockAreaRect.width += sideBorder; - } - } - private void DrawView(Rect viewRect, Rect dockAreaRect) { InvokeOnGUI(dockAreaRect, viewRect); @@ -455,14 +429,6 @@ private void DrawDockTitleBarBackground(Rect titleBarRect) } } - private static void FixDockAreaRectBorders(bool customBorder, ref Rect dockAreaRect) - { - if (!customBorder) - return; - dockAreaRect.y += 1f; - dockAreaRect.height -= 1f; - } - private void SetupHoldScrollerUpdate(float clickOffset) { m_HoldScrollOffset = clickOffset; diff --git a/Editor/Mono/GUI/EditModeTools/PrimitiveColliderTool.cs b/Editor/Mono/GUI/EditModeTools/PrimitiveColliderTool.cs new file mode 100644 index 0000000000..0e7c237742 --- /dev/null +++ b/Editor/Mono/GUI/EditModeTools/PrimitiveColliderTool.cs @@ -0,0 +1,71 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using UnityEditor.EditorTools; +using UnityEditor.IMGUI.Controls; +using UnityEngine; + +namespace UnityEditor +{ + abstract class PrimitiveColliderTool : EditorTool where T : Collider + { + public override GUIContent toolbarIcon + { + get { return PrimitiveBoundsHandle.editModeButton; } + } + + protected abstract PrimitiveBoundsHandle boundsHandle { get; } + + protected abstract void CopyColliderPropertiesToHandle(T collider); + + protected abstract void CopyHandlePropertiesToCollider(T collider); + + protected Vector3 InvertScaleVector(Vector3 scaleVector) + { + for (int axis = 0; axis < 3; ++axis) + scaleVector[axis] = scaleVector[axis] == 0f ? 0f : 1f / scaleVector[axis]; + + return scaleVector; + } + + public override void OnToolGUI(EditorWindow window) + { + foreach (var obj in targets) + { + var collider = (T)obj; + + if (Mathf.Approximately(collider.transform.lossyScale.sqrMagnitude, 0f)) + continue; + + // collider matrix is center multiplied by transform's matrix with custom postmultiplied lossy scale matrix + using (new Handles.DrawingScope(Matrix4x4.TRS(collider.transform.position, collider.transform.rotation, Vector3.one))) + { + CopyColliderPropertiesToHandle(collider); + + boundsHandle.SetColor(collider.enabled ? Handles.s_ColliderHandleColor : Handles.s_ColliderHandleColorDisabled); + + EditorGUI.BeginChangeCheck(); + + boundsHandle.DrawHandle(); + + if (EditorGUI.EndChangeCheck()) + { + Undo.RecordObject(collider, string.Format("Modify {0}", ObjectNames.NicifyVariableName(target.GetType().Name))); + CopyHandlePropertiesToCollider(collider); + } + } + } + } + + protected static Vector3 TransformColliderCenterToHandleSpace(Transform colliderTransform, Vector3 colliderCenter) + { + return Handles.inverseMatrix * (colliderTransform.localToWorldMatrix * colliderCenter); + } + + protected static Vector3 TransformHandleCenterToColliderSpace(Transform colliderTransform, Vector3 handleCenter) + { + return colliderTransform.localToWorldMatrix.inverse * (Handles.matrix * handleCenter); + } + } +} diff --git a/Editor/Mono/GUI/EditorApplicationLayout.cs b/Editor/Mono/GUI/EditorApplicationLayout.cs index 4277a830c6..93f1549d39 100644 --- a/Editor/Mono/GUI/EditorApplicationLayout.cs +++ b/Editor/Mono/GUI/EditorApplicationLayout.cs @@ -23,13 +23,13 @@ namespace UnityEditor { internal class EditorApplicationLayout { - static private GameView m_GameView = null; + static private PreviewEditorWindow m_PreviewWindow = null; static private bool m_MaximizePending = false; static internal bool IsInitializingPlaymodeLayout() { - return m_GameView != null; + return m_PreviewWindow != null; } static internal void SetPlaymodeLayout() @@ -52,33 +52,33 @@ static internal void SetPausemodeLayout() static internal void InitPlaymodeLayout() { - m_GameView = WindowLayout.ShowAppropriateViewOnEnterExitPlaymode(true) as GameView; - if (m_GameView == null) + m_PreviewWindow = WindowLayout.ShowAppropriateViewOnEnterExitPlaymode(true) as PreviewEditorWindow; + if (m_PreviewWindow == null) return; - if (m_GameView.maximizeOnPlay) + if (m_PreviewWindow.maximizeOnPlay) { - DockArea da = m_GameView.m_Parent as DockArea; + DockArea da = m_PreviewWindow.m_Parent as DockArea; if (da != null) m_MaximizePending = WindowLayout.MaximizePrepare(da.actualView); } - // Mark this game view as the start gameview so the backend - // can set size and mouseoffset properly for this game view - m_GameView.m_Parent.SetAsStartView(); + // Mark this preview window as the start preview so the backend + // can set size and mouseoffset properly for this preview + m_PreviewWindow.m_Parent.SetAsStartView(); Toolbar.RepaintToolbar(); } static internal void FinalizePlaymodeLayout() { - if (m_GameView != null) + if (m_PreviewWindow != null) { if (m_MaximizePending) - WindowLayout.MaximizePresent(m_GameView); + WindowLayout.MaximizePresent(m_PreviewWindow); - m_GameView.m_Parent.ClearStartView(); + m_PreviewWindow.m_Parent.ClearStartView(); } Clear(); @@ -87,7 +87,7 @@ static internal void FinalizePlaymodeLayout() static private void Clear() { m_MaximizePending = false; - m_GameView = null; + m_PreviewWindow = null; } } } // namespace diff --git a/Editor/Mono/GUI/EditorStyles.cs b/Editor/Mono/GUI/EditorStyles.cs index 69f639e4d7..28f2f52299 100644 --- a/Editor/Mono/GUI/EditorStyles.cs +++ b/Editor/Mono/GUI/EditorStyles.cs @@ -234,6 +234,9 @@ public sealed class EditorStyles public static GUIStyle toolbarTextField { get { return s_Current.m_ToolbarTextField; } } private GUIStyle m_ToolbarTextField; + internal static GUIStyle toolbarLabel { get { return s_Current.m_ToolbarLabel; } } + private GUIStyle m_ToolbarLabel; + public static GUIStyle inspectorDefaultMargins { get { return s_Current.m_InspectorDefaultMargins; } } private GUIStyle m_InspectorDefaultMargins; @@ -363,7 +366,7 @@ internal static void UpdateSkinCache(int skinIndex) if (s_CachedStyles[skinIndex] == null) { - EditorResources.BuildCatalog(); + EditorResources.RefreshSkin(); s_CachedStyles[skinIndex] = new EditorStyles(); s_CachedStyles[skinIndex].InitSharedStyles(); @@ -408,6 +411,7 @@ private void InitSharedStyles() m_ToolbarDropDownToggleRight = GetStyle("toolbarDropDownToggleRight"); m_ToolbarCreateAddNewDropDown = GetStyle("ToolbarCreateAddNewDropDown"); m_ToolbarTextField = GetStyle("toolbarTextField"); + m_ToolbarLabel = GetStyle("ToolbarLabel"); m_ToolbarSearchField = GetStyle("ToolbarSeachTextField"); m_ToolbarSearchFieldPopup = GetStyle("ToolbarSeachTextFieldPopup"); m_ToolbarSearchFieldCancelButton = GetStyle("ToolbarSeachCancelButton"); @@ -424,10 +428,10 @@ private void InitSharedStyles() m_MinMaxHorizontalSliderThumb = GetStyle("MinMaxHorizontalSliderThumb"); m_DropDownList = GetStyle("DropDownButton"); m_MinMaxStateDropdown = GetStyle("IN MinMaxStateDropdown"); - m_BoldFont = GetStyle("BoldLabel").font; - m_StandardFont = GetStyle("Label").font; - m_MiniFont = GetStyle("MiniLabel").font; - m_MiniBoldFont = GetStyle("MiniBoldLabel").font; + m_BoldFont = EditorResources.GetBoldFont(); + m_StandardFont = EditorResources.GetNormalFont(); + m_MiniFont = EditorResources.GetSmallFont(); + m_MiniBoldFont = EditorResources.GetBoldFont(); m_ProgressBarBack = GetStyle("ProgressBarBack"); m_ProgressBarBar = GetStyle("ProgressBarBar"); m_ProgressBarText = GetStyle("ProgressBarText"); diff --git a/Editor/Mono/GUI/InternalEditorGUI.cs b/Editor/Mono/GUI/InternalEditorGUI.cs index de99b3b1eb..f210971b5b 100644 --- a/Editor/Mono/GUI/InternalEditorGUI.cs +++ b/Editor/Mono/GUI/InternalEditorGUI.cs @@ -166,7 +166,7 @@ internal static Vector2 MouseDeltaReader(Rect position, bool activated) switch (evt.GetTypeForControl(id)) { case EventType.MouseDown: - if (activated && GUIUtility.hotControl == 0 && position.Contains(evt.mousePosition) && evt.button == 0) + if (activated && GUIUtility.hotControl == 0 && GUIUtility.HitTest(position, evt) && evt.button == 0) { GUIUtility.hotControl = id; GUIUtility.keyboardControl = 0; diff --git a/Editor/Mono/GUI/PackageImport.cs b/Editor/Mono/GUI/PackageImport.cs index 561a65d373..a44d93914b 100644 --- a/Editor/Mono/GUI/PackageImport.cs +++ b/Editor/Mono/GUI/PackageImport.cs @@ -22,11 +22,6 @@ internal class PackageImport : EditorWindow [SerializeField] TreeViewState m_TreeViewState; [NonSerialized] PackageImportTreeView m_Tree; - private bool m_ShowReInstall; - private bool m_ReInstallPackage; - - public bool canReInstall { get { return m_ShowReInstall; } } - public bool doReInstall { get { return m_ShowReInstall && m_ReInstallPackage; } } public ImportPackageItem[] packageItems { get { return m_ImportPackageItems; } } private static Texture2D s_PackageIcon; @@ -55,13 +50,13 @@ public Constants() // Invoked from menu [UsedByNativeCode] - public static void ShowImportPackage(string packagePath, ImportPackageItem[] items, string packageIconPath, bool allowReInstall) + public static void ShowImportPackage(string packagePath, ImportPackageItem[] items, string packageIconPath) { if (!ValidateInput(items)) return; var window = GetWindow(true, "Import Unity Package"); - window.Init(packagePath, items, packageIconPath, allowReInstall); + window.Init(packagePath, items, packageIconPath); } public PackageImport() @@ -90,12 +85,10 @@ void DestroyCreatedIcons() } } - void Init(string packagePath, ImportPackageItem[] items, string packageIconPath, bool allowReInstall) + void Init(string packagePath, ImportPackageItem[] items, string packageIconPath) { DestroyCreatedIcons(); - m_ShowReInstall = allowReInstall; - m_ReInstallPackage = true; m_TreeViewState = null; m_Tree = null; m_ImportPackageItems = items; @@ -106,11 +99,8 @@ void Init(string packagePath, ImportPackageItem[] items, string packageIconPath, Repaint(); } - private bool ShowTreeGUI(bool reInstalling, ImportPackageItem[] items) + private bool ShowTreeGUI(ImportPackageItem[] items) { - if (reInstalling) - return true; - if (items.Length == 0) return false; @@ -134,7 +124,7 @@ public void OnGUI() if (m_Tree == null) m_Tree = new PackageImportTreeView(this, m_TreeViewState, new Rect()); - if (m_ImportPackageItems != null && ShowTreeGUI(doReInstall, m_ImportPackageItems)) + if (m_ImportPackageItems != null && ShowTreeGUI(m_ImportPackageItems)) { TopArea(); m_Tree.OnGUI(GUILayoutUtility.GetRect(1, 9999, 1, 99999)); @@ -151,7 +141,6 @@ public void OnGUI() GUILayout.Space(8); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); - ReInstallToggle(); if (GUILayout.Button("OK")) { Close(); @@ -164,17 +153,6 @@ public void OnGUI() } } - void ReInstallToggle() - { - if (m_ShowReInstall) - { - EditorGUI.BeginChangeCheck(); - bool reInstall = GUILayout.Toggle(m_ReInstallPackage, "Re-Install Package"); - if (EditorGUI.EndChangeCheck()) - m_ReInstallPackage = reInstall; - } - } - void TopArea() { const float margin = 10f; @@ -224,8 +202,6 @@ void BottomArea() m_Tree.SetAllEnabled(PackageImportTreeView.EnabledState.None); } - ReInstallToggle(); - GUILayout.FlexibleSpace(); if (GUILayout.Button(EditorGUIUtility.TrTextContent("Cancel"))) { @@ -237,19 +213,12 @@ void BottomArea() } if (GUILayout.Button(EditorGUIUtility.TrTextContent("Import"))) { - bool doImport = true; - if (doReInstall) - doImport = EditorUtility.DisplayDialog("Re-Install?", "Highlighted folders will be completely deleted first! Recommend backing up your project first. Are you sure?", "Do It", "Cancel"); + if (m_ImportPackageItems != null) + PackageUtility.ImportPackageAssets(m_PackageName, m_ImportPackageItems); - if (doImport) - { - if (m_ImportPackageItems != null) - PackageUtility.ImportPackageAssets(m_PackageName, m_ImportPackageItems, doReInstall); - - PopupWindowWithoutFocus.Hide(); - Close(); - GUIUtility.ExitGUI(); - } + PopupWindowWithoutFocus.Hide(); + Close(); + GUIUtility.ExitGUI(); } GUILayout.Space(10); diff --git a/Editor/Mono/GUI/PackageImportTreeView.cs b/Editor/Mono/GUI/PackageImportTreeView.cs index c176dc7523..633a8438d1 100644 --- a/Editor/Mono/GUI/PackageImportTreeView.cs +++ b/Editor/Mono/GUI/PackageImportTreeView.cs @@ -29,8 +29,6 @@ public enum EnabledState private PackageImport m_PackageImport; - public bool canReInstall { get { return m_PackageImport.canReInstall; } } - public bool doReInstall { get { return m_PackageImport.doReInstall; } } public ImportPackageItem[] packageItems { get { return m_PackageImport.packageItems; } } @@ -110,8 +108,8 @@ bool ItemShouldBeConsideredForEnabledCheck(PackageImportTreeViewItem pitem) return true; var item = pitem.item; - // Its a package asset, its changed or we are doing a re-install - if (item.projectAsset || !(item.isFolder || item.assetChanged || doReInstall)) + // Its a package asset or its changed + if (item.projectAsset || !(item.isFolder || item.assetChanged)) return false; return true; @@ -346,7 +344,6 @@ override public void OnRowGUI(Rect rowRect, TreeViewItem tvItem, int row, bool s bool pathConflict = (item != null) ? item.pathConflict : false; bool exists = (item != null) ? item.exists : true; bool projectAsset = (item != null) ? item.projectAsset : false; - bool doReInstall = m_PackageImportView.doReInstall; // 1. Foldout if (m_TreeView.data.IsExpandable(tvItem)) @@ -355,7 +352,7 @@ override public void OnRowGUI(Rect rowRect, TreeViewItem tvItem, int row, bool s // 2. Toggle only for items that are actually in the package. Rect toggleRect = new Rect(k_BaseIndent + tvItem.depth * indentWidth + k_FoldoutWidth, rowRect.y, k_ToggleWidth, rowRect.height); - if ((isFolder && !projectAsset) || (validItem && !projectAsset && (assetChanged || doReInstall))) + if ((isFolder && !projectAsset) || (validItem && !projectAsset && assetChanged)) DoToggle(pitem, toggleRect); using (new EditorGUI.DisabledScope(!validItem || projectAsset)) @@ -387,7 +384,7 @@ override public void OnRowGUI(Rect rowRect, TreeViewItem tvItem, int row, bool s } // 5. Optional badge ("Delete") - if (repainting && doReInstall && projectAsset) + if (repainting && projectAsset) { // FIXME: Need to enable tooltips here. Texture badge = Constants.badgeDelete.image; diff --git a/Editor/Mono/GUI/PaneDragTab.cs b/Editor/Mono/GUI/PaneDragTab.cs index c1a3c23d2f..2d905731ea 100644 --- a/Editor/Mono/GUI/PaneDragTab.cs +++ b/Editor/Mono/GUI/PaneDragTab.cs @@ -16,7 +16,6 @@ internal class PaneDragTab : GUIView #pragma warning disable 169 private static PaneDragTab s_Get; - private const float kTopThumbnailOffset = 1; private float m_TargetAlpha = 1.0f; private DropInfo.Type m_Type = (DropInfo.Type)(-1); private GUIContent m_Content; diff --git a/Editor/Mono/GUI/SplitView.cs b/Editor/Mono/GUI/SplitView.cs index 0105d78bf5..c4abe998e4 100644 --- a/Editor/Mono/GUI/SplitView.cs +++ b/Editor/Mono/GUI/SplitView.cs @@ -3,7 +3,6 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using UnityEngine; -using UnityEditor; using System; using System.Collections.Generic; @@ -461,15 +460,6 @@ public bool PerformDrop(EditorWindow dropWindow, DropInfo dropInfo, Vector2 scre return true; } - static string PosVals(float[] posVals) - { - string s = "["; - foreach (float p in posVals) - s += "" + p + ", "; - s += "]"; - return (s); - } - void MakeRoomForRect(Rect r) { Rect[] sources = new Rect[children.Length]; @@ -703,7 +693,7 @@ public void SplitGUI(Event evt) new Rect(children[0].position.x, cursor + splitState.realSizes[i] - splitState.splitSize / 2, children[0].position.width, splitState.splitSize) : new Rect(cursor + splitState.realSizes[i] - splitState.splitSize / 2, children[0].position.y, splitState.splitSize, children[0].position.height); - if (splitterRect.Contains(evt.mousePosition)) + if (GUIUtility.HitTest(splitterRect, evt)) { splitState.splitterInitialOffset = (int)pos; splitState.currentActiveSplitter = i; diff --git a/Editor/Mono/GUI/Splitter.cs b/Editor/Mono/GUI/Splitter.cs index 16a3e705f8..9a9a077bc1 100644 --- a/Editor/Mono/GUI/Splitter.cs +++ b/Editor/Mono/GUI/Splitter.cs @@ -390,7 +390,7 @@ public static void BeginSplit(SplitterState state, GUIStyle style, bool vertical new Rect(state.xOffset + g.rect.x, cursor + state.realSizes[i] - state.splitSize / 2, g.rect.width, state.splitSize) : new Rect(state.xOffset + cursor + state.realSizes[i] - state.splitSize / 2, g.rect.y, state.splitSize, g.rect.height); - if (splitterRect.Contains(Event.current.mousePosition)) + if (GUIUtility.HitTest(splitterRect, Event.current)) { state.splitterInitialOffset = pos; state.currentActiveSplitter = i; diff --git a/Editor/Mono/GUI/StructPropertyGUI.cs b/Editor/Mono/GUI/StructPropertyGUI.cs index e5d07de4ad..c9d635cd99 100644 --- a/Editor/Mono/GUI/StructPropertyGUI.cs +++ b/Editor/Mono/GUI/StructPropertyGUI.cs @@ -34,9 +34,16 @@ internal static int GetChildrenCount(SerializedProperty property) internal class StructPropertyGUI { + static class Styles + { + public static readonly GUIStyle sectionLabel = new GUIStyle(EditorStyles.label) + { + alignment = TextAnchor.UpperLeft + }; + } internal static void GenericStruct(Rect position, SerializedProperty property) { - GUI.Label(EditorGUI.IndentedRect(position), property.displayName, EditorStyles.label); + GUI.Label(EditorGUI.IndentedRect(position), property.displayName, Styles.sectionLabel); position.y += EditorGUI.kStructHeaderLineHeight; DoChildren(position, property); diff --git a/Editor/Mono/GUI/Toolbar.cs b/Editor/Mono/GUI/Toolbar.cs index 5690df03c6..a8cb2edbf5 100644 --- a/Editor/Mono/GUI/Toolbar.cs +++ b/Editor/Mono/GUI/Toolbar.cs @@ -74,6 +74,8 @@ void InitializeToolIcons() EditorGUIUtility.TrIconContent("ViewToolOrbit On", viewToolsTooltipText) }; + s_ViewToolOnOffset = s_ViewToolIcons.Length / 2; + s_LayerContent = EditorGUIUtility.TrTextContent("Layers", "Which layers are visible in the Scene views."); s_PlayIcons = new GUIContent[] @@ -98,6 +100,7 @@ void InitializeToolIcons() static GUIContent s_LayerContent; static GUIContent[] s_PlayIcons; static GUIContent s_CustomToolIcon; + static int s_ViewToolOnOffset; private static GUIContent s_AccountContent; static GUIContent s_CloudIcon; internal static event Action toolSettingsGui; @@ -110,6 +113,7 @@ static class Styles public static readonly GUIStyle buttonLeft = "AppToolbarButtonLeft"; public static readonly GUIStyle buttonRight = "AppToolbarButtonRight"; public static readonly GUIStyle commandLeft = "AppCommandLeft"; + public static readonly GUIStyle commandLeftOn = "AppCommandLeftOn"; public static readonly GUIStyle commandMid = "AppCommandMid"; public static readonly GUIStyle commandRight = "AppCommandRight"; } @@ -256,19 +260,22 @@ protected override void OldOnGUI() DoLayersDropDown(EditorToolGUI.GetThinArea(pos)); } - ReserveWidthLeft(space, ref pos); - - ReserveWidthLeft(dropdownWidth, ref pos); - if (EditorGUI.DropdownButton(EditorToolGUI.GetThinArea(pos), s_AccountContent, FocusType.Passive, Styles.dropdown)) + if (Unity.MPE.ProcessService.level == Unity.MPE.ProcessLevel.UMP_MASTER) { - ShowUserMenu(EditorToolGUI.GetThinArea(pos)); - } + ReserveWidthLeft(space, ref pos); - ReserveWidthLeft(space, ref pos); + ReserveWidthLeft(dropdownWidth, ref pos); + if (EditorGUI.DropdownButton(EditorToolGUI.GetThinArea(pos), s_AccountContent, FocusType.Passive, Styles.dropdown)) + { + ShowUserMenu(EditorToolGUI.GetThinArea(pos)); + } + + ReserveWidthLeft(space, ref pos); - ReserveWidthLeft(standardButtonWidth, ref pos); - if (GUI.Button(EditorToolGUI.GetThinArea(pos), s_CloudIcon, Styles.command)) - UnityConnectServiceCollection.instance.ShowService(HubAccess.kServiceName, true, "cloud_icon"); // Should show hub when it's done + ReserveWidthLeft(standardButtonWidth, ref pos); + if (GUI.Button(EditorToolGUI.GetThinArea(pos), s_CloudIcon, Styles.command)) + UnityConnectServiceCollection.instance.ShowService(HubAccess.kServiceName, true, "cloud_icon"); // Should show hub when it's done + } foreach (SubToolbar subToolbar in s_SubToolbars) { @@ -359,7 +366,7 @@ void DoToolButtons(Rect rect) else s_ShownToolIcons[builtinIconsLength] = s_CustomToolIcon; - s_ShownToolIcons[0] = s_ViewToolIcons[(int)Tools.viewTool + (displayTool == 0 ? s_ShownToolIcons.Length - 1 : 0)]; + s_ShownToolIcons[0] = s_ViewToolIcons[(int)Tools.viewTool + (displayTool == 0 ? s_ViewToolOnOffset : 0)]; displayTool = GUI.Toolbar(rect, displayTool, s_ShownToolIcons, s_ToolControlNames, Styles.command, GUI.ToolbarButtonSize.FitToContents); @@ -409,7 +416,7 @@ void DoPlayButtons(bool isOrWillEnterPlaymode) Color c = GUI.color + new Color(.01f, .01f, .01f, .01f); GUI.contentColor = new Color(1.0f / c.r, 1.0f / c.g, 1.0f / c.g, 1.0f / c.a); GUI.SetNextControlName("ToolbarPlayModePlayButton"); - GUILayout.Toggle(isOrWillEnterPlaymode, s_PlayIcons[buttonOffset], Styles.commandLeft); + GUILayout.Toggle(isOrWillEnterPlaymode, s_PlayIcons[buttonOffset], isPlaying ? Styles.commandLeftOn : Styles.commandLeft); GUI.backgroundColor = Color.white; if (GUI.changed) { @@ -429,12 +436,15 @@ void DoPlayButtons(bool isOrWillEnterPlaymode) GUIUtility.ExitGUI(); } - // Step playmode - GUI.SetNextControlName("ToolbarPlayModeStepButton"); - if (GUILayout.Button(s_PlayIcons[buttonOffset + 2], Styles.commandRight)) + using (new EditorGUI.DisabledScope(!isPlaying)) { - EditorApplication.Step(); - GUIUtility.ExitGUI(); + // Step playmode + GUI.SetNextControlName("ToolbarPlayModeStepButton"); + if (GUILayout.Button(s_PlayIcons[2], Styles.commandRight)) + { + EditorApplication.Step(); + GUIUtility.ExitGUI(); + } } } diff --git a/Editor/Mono/GUI/Tools/BuiltinTools.cs b/Editor/Mono/GUI/Tools/BuiltinTools.cs index 509e9c2ac7..f539e46acf 100644 --- a/Editor/Mono/GUI/Tools/BuiltinTools.cs +++ b/Editor/Mono/GUI/Tools/BuiltinTools.cs @@ -5,6 +5,7 @@ using UnityEngine; using UnityEditor.EditorTools; using UnityEditor.SceneManagement; +using UnityEditor.Snap; namespace UnityEditor { @@ -560,14 +561,14 @@ static Vector3 ResizeHandlesGUI(Rect rect, Vector3 pivot, Quaternion rotation, o // Side resizer (1D) Vector3 sideDir = (xHandle == 1 ? rotation * Vector3.right * rect.width : rotation * Vector3.up * rect.height); Vector3 slideDir = (xHandle == 1 ? rotation * Vector3.up : rotation * Vector3.right); - newPos = RectHandles.SideSlider(id, curPos, sideDir, slideDir, size, null, 0); + newPos = RectHandles.SideSlider(id, curPos, sideDir, slideDir, size, null, EditorSnapSettings.move); } else { // Corner handle (2D) Vector3 outwardsA = rotation * Vector3.right * (xHandle - 1); Vector3 outwardsB = rotation * Vector3.up * (yHandle - 1); - newPos = RectHandles.CornerSlider(id, curPos, rotation * Vector3.forward, outwardsA, outwardsB, size, RectHandles.RectScalingHandleCap, Vector2.zero); + newPos = RectHandles.CornerSlider(id, curPos, rotation * Vector3.forward, outwardsA, outwardsB, size, RectHandles.RectScalingHandleCap, EditorSnapSettings.move); } // Calculate snapping values if applicable @@ -610,8 +611,7 @@ static Vector3 ResizeHandlesGUI(Rect rect, Vector3 pivot, Quaternion rotation, o } bool scaleFromPivot = Event.current.alt; - bool squashing = EditorGUI.actionKey; - bool uniformScaling = Event.current.shift && !squashing; + bool uniformScaling = Event.current.shift; if (!scaleFromPivot) scalePivot = GetRectPointInWorld(s_StartRect, pivot, rotation, 2 - xHandle, 2 - yHandle); @@ -632,34 +632,11 @@ static Vector3 ResizeHandlesGUI(Rect rect, Vector3 pivot, Quaternion rotation, o scale = Vector3.one * refScale; } - if (squashing && xHandle == 1) - { - if (Event.current.shift) - scale.x = scale.z = 1 / Mathf.Sqrt(Mathf.Max(scale.y, 0.0001f)); - else - scale.x = 1 / Mathf.Max(scale.y, 0.0001f); - } - if (uniformScaling) { float refScale = (xHandle == 1 ? scale.y : scale.x); scale = Vector3.one * refScale; } - - if (squashing && xHandle == 1) - { - if (Event.current.shift) - scale.x = scale.z = 1 / Mathf.Sqrt(Mathf.Max(scale.y, 0.0001f)); - else - scale.x = 1 / Mathf.Max(scale.y, 0.0001f); - } - if (squashing && yHandle == 1) - { - if (Event.current.shift) - scale.y = scale.z = 1 / Mathf.Sqrt(Mathf.Max(scale.x, 0.0001f)); - else - scale.y = 1 / Mathf.Max(scale.x, 0.0001f); - } } if (xHandle == 0) diff --git a/Editor/Mono/GUI/Tools/EditorTool.cs b/Editor/Mono/GUI/Tools/EditorTool.cs index 79b643e7ed..b89feada4d 100644 --- a/Editor/Mono/GUI/Tools/EditorTool.cs +++ b/Editor/Mono/GUI/Tools/EditorTool.cs @@ -24,6 +24,11 @@ public EditorToolAttribute(string displayName, Type targetType = null) } } + public interface IDrawSelectedHandles + { + void OnDrawHandles(); + } + public abstract class EditorTool : ScriptableObject { [HideInInspector] diff --git a/Editor/Mono/GUI/Tools/EditorToolContext.cs b/Editor/Mono/GUI/Tools/EditorToolContext.cs index 1103da012d..70964bca29 100644 --- a/Editor/Mono/GUI/Tools/EditorToolContext.cs +++ b/Editor/Mono/GUI/Tools/EditorToolContext.cs @@ -605,5 +605,16 @@ internal static ScriptableObject CreateInstance(Type type, Action(s_CustomEditorTools); + s_CustomEditorTools.Clear(); } public static void EditorToolbarForTarget(GUIContent content, UObject target) @@ -39,6 +40,7 @@ public static void EditorToolbarForTarget(GUIContent content, UObject target) EditorToolContext.GetCustomEditorToolsForTarget(target, s_CustomEditorTools, true); EditorToolbar(s_CustomEditorTools); GUILayout.EndHorizontal(); + s_CustomEditorTools.Clear(); } public static void EditorToolbar(params EditorTool[] tools) diff --git a/Editor/Mono/GUI/Tools/SnapSettings.cs b/Editor/Mono/GUI/Tools/SnapSettings.cs deleted file mode 100644 index 741161ad86..0000000000 --- a/Editor/Mono/GUI/Tools/SnapSettings.cs +++ /dev/null @@ -1,154 +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 UnityEngine; -using UnityEditor; - -namespace UnityEditor -{ - internal class SnapSettings : EditorWindow - { - private static float s_MoveSnapX; - private static float s_MoveSnapY; - private static float s_MoveSnapZ; - - private static float s_ScaleSnap; - private static float s_RotationSnap; - - private static bool s_Initialized; - - private static void Initialize() - { - if (!s_Initialized) - { - s_MoveSnapX = EditorPrefs.GetFloat("MoveSnapX", 1f); - s_MoveSnapY = EditorPrefs.GetFloat("MoveSnapY", 1f); - s_MoveSnapZ = EditorPrefs.GetFloat("MoveSnapZ", 1f); - - s_ScaleSnap = EditorPrefs.GetFloat("ScaleSnap", .1f); - s_RotationSnap = EditorPrefs.GetFloat("RotationSnap", 15); - - s_Initialized = true; - } - } - - public static Vector3 move - { - get - { - Initialize(); - return new Vector3(s_MoveSnapX, s_MoveSnapY, s_MoveSnapZ); - } - set - { - EditorPrefs.SetFloat("MoveSnapX", value.x); - s_MoveSnapX = value.x; - EditorPrefs.SetFloat("MoveSnapY", value.y); - s_MoveSnapY = value.y; - EditorPrefs.SetFloat("MoveSnapZ", value.z); - s_MoveSnapZ = value.z; - } - } - - public static float scale - { - get - { - Initialize(); - return s_ScaleSnap; - } - set - { - EditorPrefs.SetFloat("ScaleSnap", value); - s_ScaleSnap = value; - } - } - - public static float rotation - { - get - { - Initialize(); - return s_RotationSnap; - } - set - { - EditorPrefs.SetFloat("RotationSnap", value); - s_RotationSnap = value; - } - } - - [MenuItem("Edit/Snap Settings...")] - static void ShowSnapSettings() - { - EditorWindow.GetWindowWithRect(new Rect(100, 100, 230, 140), true, "Snap settings"); - } - - class Styles - { - public GUIStyle buttonLeft = "ButtonLeft"; - public GUIStyle buttonMid = "ButtonMid"; - public GUIStyle buttonRight = "ButtonRight"; - public GUIContent snapAllAxes = EditorGUIUtility.TrTextContent("Snap All Axes", "Snaps selected objects to the grid"); - public GUIContent snapX = EditorGUIUtility.TrTextContent("X", "Snaps selected objects to the grid on the x axis"); - public GUIContent snapY = EditorGUIUtility.TrTextContent("Y", "Snaps selected objects to the grid on the y axis"); - public GUIContent snapZ = EditorGUIUtility.TrTextContent("Z", "Snaps selected objects to the grid on the z axis"); - public GUIContent moveX = EditorGUIUtility.TrTextContent("Move X", "Grid spacing X"); - public GUIContent moveY = EditorGUIUtility.TrTextContent("Move Y", "Grid spacing Y"); - public GUIContent moveZ = EditorGUIUtility.TrTextContent("Move Z", "Grid spacing Z"); - public GUIContent scale = EditorGUIUtility.TrTextContent("Scale", "Grid spacing for scaling"); - public GUIContent rotation = EditorGUIUtility.TrTextContent("Rotation", "Grid spacing for rotation in degrees"); - } - static Styles ms_Styles; - - void OnGUI() - { - if (ms_Styles == null) - ms_Styles = new Styles(); - - GUILayout.Space(5); - - EditorGUI.BeginChangeCheck(); - Vector3 m = move; - m.x = EditorGUILayout.FloatField(ms_Styles.moveX, m.x); - m.y = EditorGUILayout.FloatField(ms_Styles.moveY, m.y); - m.z = EditorGUILayout.FloatField(ms_Styles.moveZ, m.z); - - if (EditorGUI.EndChangeCheck()) - { - if (m.x <= 0) m.x = move.x; - if (m.y <= 0) m.y = move.y; - if (m.z <= 0) m.z = move.z; - move = m; - } - scale = EditorGUILayout.FloatField(ms_Styles.scale, scale); - rotation = EditorGUILayout.FloatField(ms_Styles.rotation, rotation); - - GUILayout.Space(5); - - bool snapX = false, snapY = false, snapZ = false; - GUILayout.BeginHorizontal(); - if (GUILayout.Button(ms_Styles.snapAllAxes, ms_Styles.buttonLeft)) { snapX = true; snapY = true; snapZ = true; } - if (GUILayout.Button(ms_Styles.snapX, ms_Styles.buttonMid)) { snapX = true; } - if (GUILayout.Button(ms_Styles.snapY, ms_Styles.buttonMid)) { snapY = true; } - if (GUILayout.Button(ms_Styles.snapZ, ms_Styles.buttonRight)) { snapZ = true; } - GUILayout.EndHorizontal(); - - if (snapX | snapY | snapZ) - { - Vector3 scaleTmp = new Vector3(1.0f / move.x, 1.0f / move.y, 1.0f / move.z); - - Undo.RecordObjects(Selection.transforms, "Snap " + (Selection.transforms.Length == 1 ? Selection.activeGameObject.name : " selection") + " to grid"); - foreach (Transform t in Selection.transforms) - { - Vector3 pos = t.position; - if (snapX) pos.x = Mathf.Round(pos.x * scaleTmp.x) / scaleTmp.x; - if (snapY) pos.y = Mathf.Round(pos.y * scaleTmp.y) / scaleTmp.y; - if (snapZ) pos.z = Mathf.Round(pos.z * scaleTmp.z) / scaleTmp.z; - t.position = pos; - } - } - } - } -} // namespace diff --git a/Editor/Mono/GUI/TreeView/AssetsTreeViewDataSource.cs b/Editor/Mono/GUI/TreeView/AssetsTreeViewDataSource.cs index 287239c5a5..b262019563 100644 --- a/Editor/Mono/GUI/TreeView/AssetsTreeViewDataSource.cs +++ b/Editor/Mono/GUI/TreeView/AssetsTreeViewDataSource.cs @@ -135,7 +135,8 @@ public override void FetchData() var property = new HierarchyProperty(rootPath); if (!root.skipValidation && !property.Find(rootInstanceID, null)) { - Debug.LogError("Root Asset with id " + rootInstanceID + " not valid!!"); + if (rootInstanceID == 0) + Debug.LogError("Root Asset with path " + rootPath + " not valid!!"); continue; } diff --git a/Editor/Mono/GUI/TreeView/GameObjectTreeViewDataSource.cs b/Editor/Mono/GUI/TreeView/GameObjectTreeViewDataSource.cs index 062f2f8f49..742bc3e5db 100644 --- a/Editor/Mono/GUI/TreeView/GameObjectTreeViewDataSource.cs +++ b/Editor/Mono/GUI/TreeView/GameObjectTreeViewDataSource.cs @@ -590,18 +590,6 @@ static void Log(string text) Debug.Log(text); } - static int FindTransformDepth(Transform transform) - { - var trans = transform.parent; - int depth = 0; - while (trans != null) - { - depth++; - trans = trans.parent; - } - return depth; - } - override public bool IsRenamingItemAllowed(TreeViewItem item) { GameObjectTreeViewItem goItem = item as GameObjectTreeViewItem; diff --git a/Editor/Mono/GUI/TreeView/TreeViewController.cs b/Editor/Mono/GUI/TreeView/TreeViewController.cs index 94e82180fc..8132a7119b 100644 --- a/Editor/Mono/GUI/TreeView/TreeViewController.cs +++ b/Editor/Mono/GUI/TreeView/TreeViewController.cs @@ -710,25 +710,6 @@ void IterateVisibleItems(int firstRow, int numVisibleRows, float rowWidth, bool hoveredItem = currentHoveredItem; } - List GetVisibleSelectedIds() - { - // Do visible items - int firstRow, lastRow; - gui.GetFirstAndLastRowVisible(out firstRow, out lastRow); - if (lastRow < 0) - return new List(); - - List ids = new List(lastRow - firstRow); - for (int row = firstRow; row < lastRow; ++row) - { - var item = data.GetItem(row); - ids.Add(item.id); - } - - List selectedVisibleIDs = (from id in ids where state.selectedIDs.Contains(id) select id).ToList(); - return selectedVisibleIDs; - } - private void ExpansionAnimationEnded(TreeViewAnimationInput setup) { // When collapsing we delay the actual collapse until the animation is done @@ -1147,22 +1128,6 @@ public void OffsetSelection(int offset) SelectionByKey(visibleRows[newIndex]); } - bool GetFirstAndLastSelected(List items, out int firstIndex, out int lastIndex) - { - firstIndex = -1; - lastIndex = -1; - for (int i = 0; i < items.Count; ++i) - { - if (state.selectedIDs.Contains(items[i].id)) - { - if (firstIndex == -1) - firstIndex = i; - lastIndex = i; // just overwrite and we will have the last in the end... - } - } - return firstIndex != -1 && lastIndex != -1; - } - public Func> getNewSelectionOverride { private get; set; } // Returns list of selected ids diff --git a/Editor/Mono/GUI/WindowLayout.cs b/Editor/Mono/GUI/WindowLayout.cs index d048f349b8..24a9aad1fe 100644 --- a/Editor/Mono/GUI/WindowLayout.cs +++ b/Editor/Mono/GUI/WindowLayout.cs @@ -40,6 +40,11 @@ internal static class WindowLayout [UsedImplicitly, RequiredByNativeCode] public static void LoadDefaultWindowPreferences() + { + LoadDefaultWindowPreferencesEx(false); + } + + public static void LoadDefaultWindowPreferencesEx(bool keepMainWindow) { InitializeLayoutPreferencesFolder(); var projectLayoutExists = File.Exists(ProjectLayoutPath); @@ -52,7 +57,7 @@ public static void LoadDefaultWindowPreferences() Debug.Assert(File.Exists(ProjectLayoutPath)); // Load the current project layout - LoadWindowLayout(ProjectLayoutPath, !projectLayoutExists); + LoadWindowLayout(ProjectLayoutPath, !projectLayoutExists, false, keepMainWindow); } [UsedImplicitly, RequiredByNativeCode] @@ -242,14 +247,14 @@ internal static EditorWindow TryGetLastFocusedWindowInSameDock() if (windowTypeName != "") type = Type.GetType(windowTypeName); - // Also get the GameView - GameView gameView = FindEditorWindowOfType(typeof(GameView)) as GameView; - if (type != null && gameView && gameView.m_Parent != null && gameView.m_Parent is DockArea) + // Also get the Preview Window + var previewWindow = PreviewEditorWindow.GetMainPreviewWindow(); + if (type != null && previewWindow && previewWindow.m_Parent != null && previewWindow.m_Parent is DockArea) { // Get all windows of that type object[] potentials = Resources.FindObjectsOfTypeAll(type); - DockArea dock = gameView.m_Parent as DockArea; + DockArea dock = previewWindow.m_Parent as DockArea; // Find the one that is actually docked together with the GameView for (int i = 0; i < potentials.Length; i++) @@ -287,14 +292,14 @@ internal static EditorWindow TryFocusAppropriateWindow(bool enteringPlaymode) { if (enteringPlaymode) { - GameView gameView = (GameView)FindEditorWindowOfType(typeof(GameView)); - if (gameView) + var previewWindow = PreviewEditorWindow.GetMainPreviewWindow(); + if (previewWindow) { - SaveCurrentFocusedWindowInSameDock(gameView); - gameView.Focus(); + SaveCurrentFocusedWindowInSameDock(previewWindow); + previewWindow.Focus(); } - return gameView; + return previewWindow; } else { @@ -826,10 +831,10 @@ public static bool LoadWindowLayout(string path, bool newProjectLayoutWasCreated containerWindow.Show(containerWindow.showMode, loadPosition: false, displayImmediately: true, setFocus: true); } - // Unmaximize maximized GameView if maximize on play is enabled - GameView gameView = GetMaximizedWindow() as GameView; - if (gameView != null && gameView.maximizeOnPlay) - Unmaximize(gameView); + // Unmaximize maximized Preview window if maximize on play is enabled + PreviewEditorWindow preview = GetMaximizedWindow() as PreviewEditorWindow; + if (preview != null && preview.maximizeOnPlay) + Unmaximize(preview); } catch (Exception ex) { @@ -982,7 +987,13 @@ 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 View FindMainView() @@ -1025,6 +1036,8 @@ public static void RevertFactorySettings(bool quitOnCancel = true) FileUtil.DeleteFileOrDirectory(ProjectLayoutPath); LoadDefaultWindowPreferences(); + ReloadWindowLayoutMenu(); + EditorUtility.Internal_UpdateAllMenus(); ShortcutIntegration.instance.RebuildShortcuts(); } } diff --git a/Editor/Mono/GUIDebugger/ElementHighlighter.cs b/Editor/Mono/GUIDebugger/ElementHighlighter.cs index 77f000479f..12384c10f5 100644 --- a/Editor/Mono/GUIDebugger/ElementHighlighter.cs +++ b/Editor/Mono/GUIDebugger/ElementHighlighter.cs @@ -46,14 +46,20 @@ public void HighlightElement(VisualElement rootElement, Rect elementRect, GUISty { var borderWidth = 1f; m_PaddingHighlighter = new VisualElement(); - m_PaddingHighlighter.style.borderColor = kSizePaddingSecondaryColor; + m_PaddingHighlighter.style.borderLeftColor = kSizePaddingSecondaryColor; + m_PaddingHighlighter.style.borderTopColor = kSizePaddingSecondaryColor; + m_PaddingHighlighter.style.borderRightColor = kSizePaddingSecondaryColor; + m_PaddingHighlighter.style.borderBottomColor = kSizePaddingSecondaryColor; m_PaddingHighlighter.style.borderLeftWidth = borderWidth; m_PaddingHighlighter.style.borderRightWidth = borderWidth; m_PaddingHighlighter.style.borderTopWidth = borderWidth; m_PaddingHighlighter.style.borderBottomWidth = borderWidth; m_PaddingHighlighter.pickingMode = PickingMode.Ignore; m_ContentHighlighter = new VisualElement(); - m_ContentHighlighter.style.borderColor = kSizeSecondaryColor; + m_ContentHighlighter.style.borderLeftColor = kSizeSecondaryColor; + m_ContentHighlighter.style.borderTopColor = kSizeSecondaryColor; + m_ContentHighlighter.style.borderRightColor = kSizeSecondaryColor; + m_ContentHighlighter.style.borderBottomColor = kSizeSecondaryColor; m_ContentHighlighter.style.borderLeftWidth = borderWidth; m_ContentHighlighter.style.borderRightWidth = borderWidth; m_ContentHighlighter.style.borderTopWidth = borderWidth; diff --git a/Editor/Mono/GUIView.cs b/Editor/Mono/GUIView.cs index a91c7dfe1f..eadd6e726c 100644 --- a/Editor/Mono/GUIView.cs +++ b/Editor/Mono/GUIView.cs @@ -54,7 +54,7 @@ protected Panel panel { if (m_Panel == null) { - m_Panel = UIElementsUtility.FindOrCreatePanel(this, ContextType.Editor); + m_Panel = UIElementsUtility.FindOrCreateEditorPanel(this); m_Panel.name = GetType().Name; m_Panel.cursorManager = m_CursorManager; m_Panel.contextualMenuManager = s_ContextualMenuManager; @@ -203,7 +203,7 @@ protected virtual void OnEnable() protected virtual void OnDisable() { if (imguiContainer.HasMouseCapture()) - MouseCaptureController.ReleaseMouse(); + imguiContainer.ReleaseMouse(); imguiContainer.RemoveFromHierarchy(); imguiContainer = null; diff --git a/Editor/Mono/GameView/GameView.cs b/Editor/Mono/GameView/GameView.cs index f4c93a0155..f45fdbe70a 100644 --- a/Editor/Mono/GameView/GameView.cs +++ b/Editor/Mono/GameView/GameView.cs @@ -3,16 +3,13 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using UnityEngine; -using System; -using System.Collections.Generic; using UnityEditorInternal; -using UnityEditor.AnimatedValues; using UnityEditor.SceneManagement; using UnityEditor.Modules; -using UnityEngine.Scripting; -using UnityEngine.Experimental.Rendering; using System.Globalization; using UnityEngine.Rendering; +using System.Linq; +using JetBrains.Annotations; /* The main GameView can be in the following states when entering playmode. @@ -33,13 +30,12 @@ Floating GameView in separate window namespace UnityEditor { [EditorWindowTitle(title = "Game", useTypeNameAsIconName = true)] - internal class GameView : EditorWindow, IHasCustomMenu, IGameViewSizeMenuUser + internal class GameView : PreviewEditorWindow, IHasCustomMenu, IGameViewSizeMenuUser { - const int kBorderSize = 5; const int kScaleSliderMinWidth = 30; const int kScaleSliderMaxWidth = 150; const int kScaleSliderSnapThreshold = 4; - const int kScaleLabelWidth = 30; + const int kScaleLabelWidth = 35; readonly Vector2 kWarningSize = new Vector2(400f, 140f); readonly Color kClearBlack = new Color(0, 0 , 0, 0); const float kMinScale = 1f; @@ -52,7 +48,7 @@ float minScale { get { - var clampedMinScale = Mathf.Min(kMinScale, ScaleThatFitsTargetInView(targetSize, viewInWindow.size)); + var clampedMinScale = Mathf.Min(kMinScale, ScaleThatFitsTargetInView(targetRenderSize, viewInWindow.size)); if (m_LowResolutionForAspectRatios[(int)currentSizeGroupType] && currentGameViewSize.sizeType == GameViewSizeType.AspectRatio) clampedMinScale = Mathf.Max(clampedMinScale, Mathf.Floor(EditorGUIUtility.pixelsPerPoint)); return clampedMinScale; @@ -60,22 +56,17 @@ float minScale } float maxScale { - get { return Mathf.Max(kMaxScale * EditorGUIUtility.pixelsPerPoint, ScaleThatFitsTargetInView(targetSize, viewInWindow.size)); } + get { return Mathf.Max(kMaxScale * EditorGUIUtility.pixelsPerPoint, ScaleThatFitsTargetInView(targetRenderSize, viewInWindow.size)); } } [SerializeField] bool m_VSyncEnabled; - [SerializeField] bool m_MaximizeOnPlay; [SerializeField] bool m_Gizmos; [SerializeField] bool m_Stats; [SerializeField] int[] m_SelectedSizes = new int[0]; // We have a selection for each game view size group (e.g standalone, android etc) - [SerializeField] int m_TargetDisplay; [SerializeField] ZoomableArea m_ZoomArea; [SerializeField] float m_defaultScale = -1f; - - [SerializeField] RenderTexture m_TargetTexture; bool m_TargetClamped; - [SerializeField] ColorSpace m_CurrentColorSpace = ColorSpace.Uninitialized; [SerializeField] Vector2 m_LastWindowPixelSize; @@ -83,6 +74,7 @@ float maxScale [SerializeField] bool m_NoCameraWarning = true; [SerializeField] bool[] m_LowResolutionForAspectRatios = new bool[0]; [SerializeField] int m_XRRenderMode = 0; + [SerializeField] RenderTexture m_RenderTexture; int m_SizeChangeID = int.MinValue; @@ -107,51 +99,24 @@ internal static class Styles static Styles() { - gameViewBackgroundStyle = (GUIStyle)"GameViewBackground"; + gameViewBackgroundStyle = "GameViewBackground"; renderdocContent = EditorGUIUtility.TrIconContent("renderdoc", UnityEditor.RenderDocUtil.openInRenderDocLabel); } }; - static List s_GameViews = new List(); - static GameView s_LastFocusedGameView = null; static double s_LastScrollTime; - static GameView s_RenderingGameView; - - class RenderingGameView : IDisposable - { - bool disposed = false; - - public RenderingGameView(GameView gameView) - { - GameView.s_RenderingGameView = gameView; - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - // Protected implementation of Dispose pattern. - protected virtual void Dispose(bool disposing) - { - if (disposed) - return; - - if (disposing) - { - GameView.s_RenderingGameView = null; - } - - disposed = true; - } - } public GameView() { autoRepaintOnSceneChange = true; - m_TargetDisplay = 0; InitializeZoomArea(); + previewName = "GameView"; + clearColor = kClearBlack; + showGizmos = m_Gizmos; + targetDisplay = 0; + targetSize = Vector2.zero; + textureFilterMode = FilterMode.Point; + textureHideFlags = HideFlags.HideAndDontSave; } public bool lowResolutionForAspectRatios @@ -172,12 +137,19 @@ public bool lowResolutionForAspectRatios } } - public bool forceLowResolutionAspectRatios { get { return EditorGUIUtility.pixelsPerPoint == 1f; } } + public bool forceLowResolutionAspectRatios => EditorGUIUtility.pixelsPerPoint == 1f; - public bool maximizeOnPlay + public bool vSyncEnabled { - get { return m_MaximizeOnPlay; } - set { m_MaximizeOnPlay = value; } + get { return m_VSyncEnabled; } + set + { + if (value == m_VSyncEnabled) + return; + + SetVSync(value); + m_VSyncEnabled = value; + } } int selectedSizeIndex @@ -194,20 +166,14 @@ int selectedSizeIndex } } - static GameViewSizeGroupType currentSizeGroupType - { - get { return GameViewSizes.instance.currentGroupType; } - } + static GameViewSizeGroupType currentSizeGroupType => GameViewSizes.instance.currentGroupType; - GameViewSize currentGameViewSize - { - get { return GameViewSizes.instance.currentGroup.GetGameViewSize(selectedSizeIndex); } - } + GameViewSize currentGameViewSize => GameViewSizes.instance.currentGroup.GetGameViewSize(selectedSizeIndex); // The area of the window that the rendered game view is limited to - Rect viewInWindow { get { return new Rect(0, EditorGUI.kWindowToolbarHeight, position.width, position.height - EditorGUI.kWindowToolbarHeight); } } + Rect viewInWindow => new Rect(0, EditorGUI.kWindowToolbarHeight, position.width, position.height - EditorGUI.kWindowToolbarHeight); - internal Vector2 targetSize // Size of render target in pixels + internal Vector2 targetRenderSize // Size of render target in pixels { get { @@ -221,7 +187,7 @@ Rect targetInContent { get { - var targetSizeCached = targetSize; + var targetSizeCached = targetRenderSize; return EditorGUIUtility.PixelsToPoints(new Rect(-0.5f * targetSizeCached, targetSizeCached)); } } @@ -279,22 +245,6 @@ Rect targetInParent // Area of the render target in parent view space } } - Rect clippedTargetInParent // targetInParent, but clipped to viewInParent to discard outside mouse events - { - get - { - var targetInParentCached = targetInParent; - var viewInParentCached = viewInParent; - var clippedTargetInParent = Rect.MinMaxRect( - Mathf.Max(targetInParentCached.xMin, viewInParentCached.xMin), - Mathf.Max(targetInParentCached.yMin, viewInParentCached.yMin), - Mathf.Min(targetInParentCached.xMax, viewInParentCached.xMax), - Mathf.Min(targetInParentCached.yMax, viewInParentCached.yMax) - ); - return clippedTargetInParent; - } - } - // Area for warnings such as no cameras rendering Rect warningPosition { get { return new Rect((viewInWindow.size - kWarningSize) * 0.5f, kWarningSize); } } @@ -304,9 +254,7 @@ Rect targetInParent // Area of the render target in parent view space void InitializeZoomArea() { - m_ZoomArea = new ZoomableArea(true, false); - m_ZoomArea.uniformScale = true; - m_ZoomArea.upDirection = ZoomableArea.YDirection.Negative; + m_ZoomArea = new ZoomableArea(true, false) {uniformScale = true, upDirection = ZoomableArea.YDirection.Negative}; } public void OnEnable() @@ -315,7 +263,6 @@ public void OnEnable() titleContent = GetLocalizedTitleContent(); UpdateZoomAreaAndParent(); dontClearBackground = true; - s_GameViews.Add(this); EditorApplication.playModeStateChanged += OnPlayModeStateChanged; } @@ -323,64 +270,16 @@ public void OnEnable() public void OnDisable() { EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; - - s_GameViews.Remove(this); - if (m_TargetTexture) + if (m_RenderTexture) { - DestroyImmediate(m_TargetTexture); + DestroyImmediate(m_RenderTexture); } } - internal static bool IsGameViewOpen() - { - if (GetMainGameView() == null) - return false; - - return true; - } - - internal static GameView GetMainGameView() - { - if (s_LastFocusedGameView == null && s_GameViews != null && s_GameViews.Count > 0) - s_LastFocusedGameView = s_GameViews[0]; - - return s_LastFocusedGameView; - } - - internal static GameView GetRenderingGameView() - { - return s_RenderingGameView; - } - - public static void RepaintAll() - { - if (s_GameViews == null) - return; - - foreach (GameView gv in s_GameViews) - gv.Repaint(); - } - - // This is here because NGUI uses it via reflection (noted in https://confluence.hq.unity3d.com/display/DEV/Game+View+Bucket) + [UsedImplicitly] // This is here because NGUI uses it via reflection (noted in https://confluence.hq.unity3d.com/display/DEV/Game+View+Bucket) internal static Vector2 GetSizeOfMainGameView() { - return GetMainGameViewTargetSize(); - } - - internal static Vector2 GetMainGameViewTargetSize() - { - var gameView = GetMainGameView(); - // It's possible with a corrupted layout that a GameView doesn't have a parent view. - if (gameView != null && gameView.m_Parent) - return gameView.targetSize; - else - return new Vector2(640f, 480f); - } - - [RequiredByNativeCode] - private static void GetMainGameViewTargetSizeNoBox(out Vector2 result) - { - result = GetMainGameViewTargetSize(); + return GetMainPreviewTargetSize(); } private void UpdateZoomAreaAndParent() @@ -388,7 +287,7 @@ private void UpdateZoomAreaAndParent() // Configure ZoomableArea for new resolution so that old resolution doesn't restrict scale bool oldScaleWasDefault = Mathf.Approximately(m_ZoomArea.scale.y, m_defaultScale); ConfigureZoomArea(); - m_defaultScale = DefaultScaleForTargetInView(targetSize, viewInWindow.size); + m_defaultScale = DefaultScaleForTargetInView(targetRenderSize, viewInWindow.size); if (oldScaleWasDefault) { m_ZoomArea.SetTransform(Vector2.zero, Vector2.one * m_defaultScale); @@ -402,7 +301,7 @@ private void UpdateZoomAreaAndParent() m_ZoomArea.UpdateZoomScale(maxScale, minScale); } - void AllowCursorLockAndHide(bool enable) + protected void AllowCursorLockAndHide(bool enable) { Unsupported.SetAllowCursorLock(enable, Unsupported.DisallowCursorLockReasons.Other); Unsupported.SetAllowCursorHide(enable); @@ -411,8 +310,7 @@ void AllowCursorLockAndHide(bool enable) private void OnFocus() { AllowCursorLockAndHide(true); - s_LastFocusedGameView = this; - InternalEditorUtility.OnGameViewFocus(true); + SetFocus(true); } private void OnLostFocus() @@ -425,8 +323,7 @@ private void OnLostFocus() { AllowCursorLockAndHide(false); } - - InternalEditorUtility.OnGameViewFocus(false); + SetFocus(false); } // Call when number of available aspects can have changed (after deserialization or gui change) @@ -459,17 +356,6 @@ private void EnsureSelectedSizeAreValid() m_LowResolutionForAspectRatios[groupIndex] = GameViewSizes.DefaultLowResolutionSettingForSizeGroupType((GameViewSizeGroupType)sizeGroupTypes.GetValue(groupIndex)); } - public bool IsShowingGizmos() - { - return m_Gizmos; - } - - public void SetShowGizmos(bool value) - { - m_Gizmos = value; - Repaint(); - } - private void OnSelectionChange() { if (m_Gizmos) @@ -576,12 +462,25 @@ private void DoToolbarGUI() GUILayout.BeginHorizontal(EditorStyles.toolbar); { + var types = GetAvailableWindowTypes(); + if (types.Count > 1) + { + int viewIndex = EditorGUILayout.Popup(types.IndexOf(typeof(GameView)), types.Select(viewTypes => viewTypes.Name).ToArray(), + EditorStyles.toolbarPopup, + GUILayout.Width(90)); + EditorGUILayout.Space(); + if (types[viewIndex].Name != typeof(GameView).Name) + { + SwapMainWindow(types[viewIndex]); + } + } + if (ModuleManager.ShouldShowMultiDisplayOption()) { - int display = EditorGUILayout.Popup(m_TargetDisplay, DisplayUtility.GetDisplayNames(), EditorStyles.toolbarPopup, GUILayout.Width(80)); - if (display != m_TargetDisplay) + int display = EditorGUILayout.Popup(targetDisplay, DisplayUtility.GetDisplayNames(), EditorStyles.toolbarPopup, GUILayout.Width(80)); + if (display != targetDisplay) { - m_TargetDisplay = display; + targetDisplay = display; UpdateZoomAreaAndParent(); } } @@ -632,10 +531,9 @@ private void DoToolbarGUI() SetXRRenderMode(selectedRenderMode); } - m_MaximizeOnPlay = GUILayout.Toggle(m_MaximizeOnPlay, Styles.maximizeOnPlayContent, EditorStyles.toolbarButton); - EditorUtility.audioMasterMute = GUILayout.Toggle(EditorUtility.audioMasterMute, Styles.muteContent, EditorStyles.toolbarButton); + maximizeOnPlay = GUILayout.Toggle(maximizeOnPlay, Styles.maximizeOnPlayContent, EditorStyles.toolbarButton); - DoVSyncButton(); + EditorUtility.audioMasterMute = GUILayout.Toggle(EditorUtility.audioMasterMute, Styles.muteContent, EditorStyles.toolbarButton); m_Stats = GUILayout.Toggle(m_Stats, Styles.statsContent, EditorStyles.toolbarButton); @@ -651,29 +549,11 @@ private void DoToolbarGUI() GUILayout.EndHorizontal(); } - private void DoVSyncButton() - { - // Only show the vsync toggle for editor supported gfx device backend. - var gfxDeviceType = SystemInfo.graphicsDeviceType; - if (gfxDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Metal || - gfxDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Vulkan || - gfxDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Direct3D11 || - gfxDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Direct3D12 || - gfxDeviceType == UnityEngine.Rendering.GraphicsDeviceType.OpenGLCore) - { - EditorGUI.BeginChangeCheck(); - m_VSyncEnabled = GUILayout.Toggle(m_VSyncEnabled, Styles.vsyncContent, EditorStyles.toolbarButton); - if (EditorGUI.EndChangeCheck() && EditorApplication.isPlaying) - m_Parent.EnableVSync(m_VSyncEnabled); - } - } - private void SetXRRenderMode(int mode) { switch (mode) { - case 0: - default: + default: // or 0 UnityEngine.XR.XRSettings.gameViewRenderMode = UnityEngine.XR.GameViewRenderMode.LeftEye; break; case 1: @@ -695,52 +575,15 @@ private void SetXRRenderMode(int mode) private void ClearTargetTexture() { - if (m_TargetTexture.IsCreated()) + if (m_RenderTexture.IsCreated()) { var previousTarget = RenderTexture.active; - RenderTexture.active = m_TargetTexture; + RenderTexture.active = m_RenderTexture; GL.Clear(true, true, kClearBlack); RenderTexture.active = previousTarget; } } - private void ConfigureTargetTexture(int width, int height) - { - var clearTexture = false; - // Changing color space requires destroying the entire RT object and recreating it - if (m_TargetTexture && m_CurrentColorSpace != QualitySettings.activeColorSpace) - { - DestroyImmediate(m_TargetTexture); - } - if (!m_TargetTexture) - { - m_CurrentColorSpace = QualitySettings.activeColorSpace; - m_TargetTexture = new RenderTexture(0, 0, 24, SystemInfo.GetGraphicsFormat(DefaultFormat.LDR)); - m_TargetTexture.name = "GameView RT"; - m_TargetTexture.filterMode = FilterMode.Point; - m_TargetTexture.hideFlags = HideFlags.HideAndDontSave; - } - - // Changes to these attributes require a release of the texture - if (m_TargetTexture.width != width || m_TargetTexture.height != height) - { - m_TargetTexture.Release(); - m_TargetTexture.width = width; - m_TargetTexture.height = height; - m_TargetTexture.antiAliasing = 1; - clearTexture = true; - if (m_TargetClamped) - Debug.LogWarningFormat("GameView reduced to a reasonable size for this system ({0}x{1})", width, height); - } - - m_TargetTexture.Create(); - - if (clearTexture) - { - ClearTargetTexture(); - } - } - private float ScaleThatFitsTargetInView(Vector2 targetInPixels, Vector2 viewInPoints) { var targetInPoints = EditorGUIUtility.PixelsToPoints(targetInPixels); @@ -802,22 +645,13 @@ private void EnforceZoomAreaConstraints() public void RenderToHMDOnly() { - ConfigureTargetTexture((int)targetSize.x, (int)targetSize.y); - - if (m_TargetTexture.IsCreated()) - { - var gizmos = false; - var targetDisplay = 0; - var sendInput = false; + var mousePos = Vector2.zero; + targetDisplay = 0; + targetSize = targetRenderSize; + showGizmos = false; + renderIMGUI = false; - EditorGUIUtility.RenderGameViewCamerasInternal( - m_TargetTexture, - targetDisplay, - GUIClip.Unclip(viewInWindow), - Vector2.zero, - gizmos, - sendInput); - } + m_RenderTexture = RenderPreview(mousePos, clearTexture: false); } private void OnPlayModeStateChanged(PlayModeStateChange state) @@ -835,175 +669,176 @@ private void OnPlayModeStateChanged(PlayModeStateChange state) private void OnGUI() { - using (var rgv = new RenderingGameView(this)) + if (position.size * EditorGUIUtility.pixelsPerPoint != m_LastWindowPixelSize) // pixelsPerPoint only reliable in OnGUI() { - if (position.size * EditorGUIUtility.pixelsPerPoint != m_LastWindowPixelSize) // pixelsPerPoint only reliable in OnGUI() - { - UpdateZoomAreaAndParent(); - } + UpdateZoomAreaAndParent(); + } - DoToolbarGUI(); + DoToolbarGUI(); - // This isn't ideal. Custom Cursors set by editor extensions for other windows can leak into the game view. - // To fix this we should probably stop using the global custom cursor (intended for runtime) for custom editor cursors. - // This has been noted for Cursors tech debt. - EditorGUIUtility.AddCursorRect(viewInWindow, MouseCursor.CustomCursor); + // This isn't ideal. Custom Cursors set by editor extensions for other windows can leak into the game view. + // To fix this we should probably stop using the global custom cursor (intended for runtime) for custom editor cursors. + // This has been noted for Cursors tech debt. + EditorGUIUtility.AddCursorRect(viewInWindow, MouseCursor.CustomCursor); - EventType type = Event.current.type; + EventType type = Event.current.type; - // Gain mouse lock when clicking on game view content - if (type == EventType.MouseDown && viewInWindow.Contains(Event.current.mousePosition)) - { - AllowCursorLockAndHide(true); - } - // Lose mouse lock when pressing escape - else if (type == EventType.KeyDown && Event.current.keyCode == KeyCode.Escape) - { - AllowCursorLockAndHide(false); - } + // Gain mouse lock when clicking on game view content + if (type == EventType.MouseDown && viewInWindow.Contains(Event.current.mousePosition)) + { + AllowCursorLockAndHide(true); + } + // Lose mouse lock when pressing escape + else if (type == EventType.KeyDown && Event.current.keyCode == KeyCode.Escape) + { + AllowCursorLockAndHide(false); + } - // We hide sliders when playing, and also when we are zoomed out beyond canvas edges - var playing = EditorApplication.isPlaying && !EditorApplication.isPaused; - var targetInContentCached = targetInContent; - m_ZoomArea.hSlider = !playing && m_ZoomArea.shownArea.width < targetInContentCached.width; - m_ZoomArea.vSlider = !playing && m_ZoomArea.shownArea.height < targetInContentCached.height; - m_ZoomArea.enableMouseInput = !playing; - ConfigureZoomArea(); + // We hide sliders when playing, and also when we are zoomed out beyond canvas edges + var playing = EditorApplication.isPlaying && !EditorApplication.isPaused; + var targetInContentCached = targetInContent; + m_ZoomArea.hSlider = !playing && m_ZoomArea.shownArea.width < targetInContentCached.width; + m_ZoomArea.vSlider = !playing && m_ZoomArea.shownArea.height < targetInContentCached.height; + m_ZoomArea.enableMouseInput = !playing; + ConfigureZoomArea(); - // We don't want controls inside the GameView (e.g. the toolbar) to have keyboard focus while playing. - // The game should get the keyboard events. - if (playing) - EditorGUIUtility.keyboardControl = 0; + // We don't want controls inside the GameView (e.g. the toolbar) to have keyboard focus while playing. + // The game should get the keyboard events. + if (playing) + EditorGUIUtility.keyboardControl = 0; - GUI.color = Color.white; // Get rid of play mode tint + GUI.color = Color.white; // Get rid of play mode tint - var originalEventType = Event.current.type; + var originalEventType = Event.current.type; - m_ZoomArea.BeginViewGUI(); + m_ZoomArea.BeginViewGUI(); - // Setup game view dimensions, so that player loop can use it for input - var gameViewTarget = GUIClip.UnclipToWindow(m_ZoomArea.drawRect); - if (m_Parent) - { - var zoomedTarget = new Rect(targetInView.position + gameViewTarget.position, targetInView.size); - SetParentGameViewDimensions(zoomedTarget, gameViewTarget, targetSize); - } + // Setup game view dimensions, so that player loop can use it for input + var gameViewTarget = GUIClip.UnclipToWindow(m_ZoomArea.drawRect); + if (m_Parent) + { + var zoomedTarget = new Rect(targetInView.position + gameViewTarget.position, targetInView.size); + SetParentGameViewDimensions(zoomedTarget, gameViewTarget, targetRenderSize); + } - var editorMousePosition = Event.current.mousePosition; - var gameMousePosition = (editorMousePosition + gameMouseOffset) * gameMouseScale; + var editorMousePosition = Event.current.mousePosition; + var gameMousePosition = (editorMousePosition + gameMouseOffset) * gameMouseScale; - if (type == EventType.Repaint) - { - GUI.Box(m_ZoomArea.drawRect, GUIContent.none, Styles.gameViewBackgroundStyle); + if (type == EventType.Repaint) + { + GUI.Box(m_ZoomArea.drawRect, GUIContent.none, Styles.gameViewBackgroundStyle); - Vector2 oldOffset = GUIUtility.s_EditorScreenPointOffset; - GUIUtility.s_EditorScreenPointOffset = Vector2.zero; - SavedGUIState oldState = SavedGUIState.Create(); + Vector2 oldOffset = GUIUtility.s_EditorScreenPointOffset; + GUIUtility.s_EditorScreenPointOffset = Vector2.zero; + SavedGUIState oldState = SavedGUIState.Create(); - ConfigureTargetTexture((int)targetSize.x, (int)targetSize.y); - if (m_ClearInEditMode && !EditorApplication.isPlaying) - ClearTargetTexture(); + var clearTexture = m_ClearInEditMode && !EditorApplication.isPlaying; - var currentTargetDisplay = 0; - if (ModuleManager.ShouldShowMultiDisplayOption()) - { - // Display Targets can have valid targets from 0 to 7. - System.Diagnostics.Debug.Assert(m_TargetDisplay < 8, "Display Target is Out of Range"); - currentTargetDisplay = m_TargetDisplay; - } - if (m_TargetTexture.IsCreated()) - { - var sendInput = true; - if (!EditorApplication.isPlaying || (EditorApplication.isPlaying && Time.frameCount % OnDemandRendering.GetRenderFrameInterval() == 0)) - EditorGUIUtility.RenderGameViewCamerasInternal(m_TargetTexture, currentTargetDisplay, GUIClip.Unclip(viewInWindow), gameMousePosition, m_Gizmos, sendInput); - - oldState.ApplyAndForget(); - GUIUtility.s_EditorScreenPointOffset = oldOffset; - - GUI.BeginGroup(m_ZoomArea.drawRect); - // Actually draw the game view to the screen, without alpha blending - Rect drawRect = deviceFlippedTargetInView; - drawRect.x = Mathf.Round(drawRect.x); - drawRect.y = Mathf.Round(drawRect.y); - Graphics.DrawTexture(drawRect, m_TargetTexture, new Rect(0, 0, 1, 1), 0, 0, 0, 0, GUI.color, GUI.blitMaterial); - GUI.EndGroup(); - } - } - else if (type != EventType.Layout && type != EventType.Used) + var currentTargetDisplay = 0; + if (ModuleManager.ShouldShowMultiDisplayOption()) { - if (Event.current.isKey && (!EditorApplication.isPlaying || EditorApplication.isPaused)) - return; + // Display Targets can have valid targets from 0 to 7. + System.Diagnostics.Debug.Assert(targetDisplay < 8, "Display Target is Out of Range"); + currentTargetDisplay = targetDisplay; + } - bool mousePosInGameViewRect = viewInWindow.Contains(Event.current.mousePosition); + targetDisplay = currentTargetDisplay; + targetSize = targetRenderSize; + showGizmos = m_Gizmos; + clearColor = kClearBlack; + renderIMGUI = true; - // MouseDown events outside game view rect are not send to scripts but MouseUp events are (see below) - if (Event.current.rawType == EventType.MouseDown && !mousePosInGameViewRect) - return; + if (!EditorApplication.isPlaying || (EditorApplication.isPlaying && Time.frameCount % OnDemandRendering.GetRenderFrameInterval() == 0)) + m_RenderTexture = RenderPreview(gameMousePosition, clearTexture); + if (m_TargetClamped) + Debug.LogWarningFormat("GameView reduced to a reasonable size for this system ({0}x{1})", targetSize.x, targetSize.y); + EditorGUIUtility.SetupWindowSpaceAndVSyncInternal(GUIClip.Unclip(viewInWindow)); - var originalDisplayIndex = Event.current.displayIndex; + if (m_RenderTexture.IsCreated()) + { + oldState.ApplyAndForget(); + GUIUtility.s_EditorScreenPointOffset = oldOffset; + + GUI.BeginGroup(m_ZoomArea.drawRect); + // Actually draw the game view to the screen, without alpha blending + Rect drawRect = deviceFlippedTargetInView; + drawRect.x = Mathf.Round(drawRect.x); + drawRect.y = Mathf.Round(drawRect.y); + Graphics.DrawTexture(drawRect, m_RenderTexture, new Rect(0, 0, 1, 1), 0, 0, 0, 0, GUI.color, GUI.blitMaterial); + GUI.EndGroup(); + } + } + else if (type != EventType.Layout && type != EventType.Used) + { + if (Event.current.isKey && (!EditorApplication.isPlaying || EditorApplication.isPaused)) + return; + + bool mousePosInGameViewRect = viewInWindow.Contains(Event.current.mousePosition); - // Transform events into local space, so the mouse position is correct - // Then queue it up for playback during playerloop - Event.current.mousePosition = gameMousePosition; - Event.current.displayIndex = m_TargetDisplay; + // MouseDown events outside game view rect are not send to scripts but MouseUp events are (see below) + if (Event.current.rawType == EventType.MouseDown && !mousePosInGameViewRect) + return; - EditorGUIUtility.QueueGameViewInputEvent(Event.current); + var originalDisplayIndex = Event.current.displayIndex; - bool useEvent = true; + // Transform events into local space, so the mouse position is correct + // Then queue it up for playback during playerloop + Event.current.mousePosition = gameMousePosition; + Event.current.displayIndex = targetDisplay; - // Do not use mouse UP event if mousepos is outside game view rect (fix for case 380995: Gameview tab's context menu is not appearing on right click) - // Placed after event queueing above to ensure scripts can react on mouse up events. - if (Event.current.rawType == EventType.MouseUp && !mousePosInGameViewRect) - useEvent = false; + EditorGUIUtility.QueueGameViewInputEvent(Event.current); - // Don't use command events, or they won't be sent to other views. - if (type == EventType.ExecuteCommand || type == EventType.ValidateCommand) - useEvent = false; + // Do not use mouse UP event if mousepos is outside game view rect (fix for case 380995: Gameview tab's context menu is not appearing on right click) + // Placed after event queueing above to ensure scripts can react on mouse up events. + bool useEvent = !(Event.current.rawType == EventType.MouseUp && !mousePosInGameViewRect); - if (useEvent) - Event.current.Use(); - else - Event.current.mousePosition = editorMousePosition; + // Don't use command events, or they won't be sent to other views. + if (type == EventType.ExecuteCommand || type == EventType.ValidateCommand) + useEvent = false; - // Reset display index - Event.current.displayIndex = originalDisplayIndex; - } + if (useEvent) + Event.current.Use(); + else + Event.current.mousePosition = editorMousePosition; - m_ZoomArea.EndViewGUI(); + // Reset display index + Event.current.displayIndex = originalDisplayIndex; + } - if (originalEventType == EventType.ScrollWheel && Event.current.type == EventType.Used) - { - EditorApplication.update -= SnapZoomDelayed; - EditorApplication.update += SnapZoomDelayed; - s_LastScrollTime = EditorApplication.timeSinceStartup; - } + m_ZoomArea.EndViewGUI(); - EnforceZoomAreaConstraints(); + if (originalEventType == EventType.ScrollWheel && Event.current.type == EventType.Used) + { + EditorApplication.update -= SnapZoomDelayed; + EditorApplication.update += SnapZoomDelayed; + s_LastScrollTime = EditorApplication.timeSinceStartup; + } - if (m_TargetTexture) + EnforceZoomAreaConstraints(); + + if (m_RenderTexture) + { + if (m_ZoomArea.scale.y < 1f) { - if (m_ZoomArea.scale.y < 1f) - { - m_TargetTexture.filterMode = FilterMode.Bilinear; - } - else - { - m_TargetTexture.filterMode = FilterMode.Point; - } + m_RenderTexture.filterMode = FilterMode.Bilinear; } - - if (m_NoCameraWarning && !EditorGUIUtility.IsDisplayReferencedByCameras(m_TargetDisplay)) + else { - GUI.Label(warningPosition, GUIContent.none, EditorStyles.notificationBackground); - var displayName = ModuleManager.ShouldShowMultiDisplayOption() ? DisplayUtility.GetDisplayNames()[m_TargetDisplay].text : string.Empty; - var cameraWarning = string.Format("{0}\nNo cameras rendering", displayName); - EditorGUI.DoDropShadowLabel(warningPosition, EditorGUIUtility.TempContent(cameraWarning), EditorStyles.notificationText, .3f); + m_RenderTexture.filterMode = FilterMode.Point; } + } - if (m_Stats) - GameViewGUI.GameViewStatsGUI(); + if (m_NoCameraWarning && !EditorGUIUtility.IsDisplayReferencedByCameras(targetDisplay)) + { + GUI.Label(warningPosition, GUIContent.none, EditorStyles.notificationBackground); + var displayName = ModuleManager.ShouldShowMultiDisplayOption() ? DisplayUtility.GetDisplayNames()[targetDisplay].text : string.Empty; + var cameraWarning = string.Format("{0}\nNo cameras rendering", displayName); + EditorGUI.DoDropShadowLabel(warningPosition, EditorGUIUtility.TempContent(cameraWarning), EditorStyles.notificationText, .3f); } + + if (m_Stats) + GameViewGUI.GameViewStatsGUI(); } } } diff --git a/Editor/Mono/GameView/GameViewSizeMenu.cs b/Editor/Mono/GameView/GameViewSizeMenu.cs index be06717481..ccb3b036ac 100644 --- a/Editor/Mono/GameView/GameViewSizeMenu.cs +++ b/Editor/Mono/GameView/GameViewSizeMenu.cs @@ -10,11 +10,16 @@ namespace UnityEditor // Resolution/Aspect ratio menu for the GameView, with an optional toggle for low-resolution aspect ratios internal class GameViewSizeMenu : FlexibleMenu { + static class Styles + { + public static GUIContent vSyncToggleContent = EditorGUIUtility.TrTextContent("VSync (Game view only)", "Enable VSync only for the game view while in playmode."); + } + const float kTopMargin = 7f; const float kMargin = 9f; IGameViewSizeMenuUser m_GameView; - float frameHeight { get { return kTopMargin * 2 + EditorGUI.kSingleLineHeight; } } + float frameHeight { get { return kTopMargin * 2 + EditorGUI.kSingleLineHeight * (IsVSyncToggleVisible() ? 2 : 1); } } float contentOffset { get { return frameHeight + EditorGUI.kControlVerticalSpacing; } } public GameViewSizeMenu(IFlexibleMenuItemProvider itemProvider, int selectionIndex, FlexibleMenuModifyItemUI modifyItemUi, IGameViewSizeMenuUser gameView) @@ -32,6 +37,25 @@ public override Vector2 GetWindowSize() return size; } + private bool IsVSyncToggleVisible() + { + // Only show the vsync toggle for editor supported gfx device backend. + var gfxDeviceType = SystemInfo.graphicsDeviceType; + return gfxDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Metal || + gfxDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Vulkan || + gfxDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Direct3D11 || + gfxDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Direct3D12 || + gfxDeviceType == UnityEngine.Rendering.GraphicsDeviceType.OpenGLCore; + } + + private void DoVSyncToggle(Rect rect) + { + if (!IsVSyncToggleVisible()) + return; + var toggleRect = new Rect(rect.xMin, rect.yMax + 2, rect.width, EditorGUI.kSingleLineHeight); + m_GameView.vSyncEnabled = GUI.Toggle(toggleRect, m_GameView.vSyncEnabled, Styles.vSyncToggleContent); + } + public override void OnGUI(Rect rect) { var frameRect = new Rect(rect.x, rect.y, rect.width, frameHeight); @@ -40,10 +64,12 @@ public override void OnGUI(Rect rect) GUI.enabled = !m_GameView.forceLowResolutionAspectRatios; var toggleRect = new Rect(kMargin, kTopMargin, rect.width, EditorGUI.kSingleLineHeight); - m_GameView.lowResolutionForAspectRatios = GUI.Toggle(toggleRect, m_GameView.forceLowResolutionAspectRatios ? true : m_GameView.lowResolutionForAspectRatios, GameView.Styles.lowResAspectRatiosContextMenuContent); + m_GameView.lowResolutionForAspectRatios = GUI.Toggle(toggleRect, m_GameView.forceLowResolutionAspectRatios || m_GameView.lowResolutionForAspectRatios, GameView.Styles.lowResAspectRatiosContextMenuContent); GUI.enabled = true; + DoVSyncToggle(toggleRect); + rect.height = rect.height - contentOffset; rect.y = rect.y + contentOffset; base.OnGUI(rect); diff --git a/Editor/Mono/GameView/IGameViewSizeMenuUser.cs b/Editor/Mono/GameView/IGameViewSizeMenuUser.cs index d2ed188a87..ff43698b8a 100644 --- a/Editor/Mono/GameView/IGameViewSizeMenuUser.cs +++ b/Editor/Mono/GameView/IGameViewSizeMenuUser.cs @@ -9,5 +9,6 @@ internal interface IGameViewSizeMenuUser void SizeSelectionCallback(int indexClicked, object objectSelected); bool lowResolutionForAspectRatios { get; set; } bool forceLowResolutionAspectRatios { get; } + bool vSyncEnabled { get; set; } } } diff --git a/Editor/Mono/GenerateIconsWithMipLevels.cs b/Editor/Mono/GenerateIconsWithMipLevels.cs index 4935190f68..edd4c55b2c 100644 --- a/Editor/Mono/GenerateIconsWithMipLevels.cs +++ b/Editor/Mono/GenerateIconsWithMipLevels.cs @@ -117,21 +117,7 @@ public static void GenerateSelectedIconsWithMips() int instanceID = Selection.activeInstanceID; string assetPath = AssetDatabase.GetAssetPath(instanceID); - if (!VerifyIconPath(assetPath, true)) - return; - - float startTime = Time.realtimeSinceStartup; - var data = GetInputData(); - string baseName = assetPath.Replace(data.sourceFolder, ""); - baseName = baseName.Substring(0, baseName.LastIndexOf(data.mipIdentifier, StringComparison.Ordinal)); - - string cwd = new DirectoryInfo(data.sourceFolder).FullName; - List assetPaths = GetIconAssetPaths(cwd, data.sourceFolder, data.mipIdentifier, data.mipFileExtension); - - EnsureFolderIsCreated(data.targetFolder); - GenerateIcon(data, baseName, assetPaths, null, null); - Debug.Log(string.Format("Generated {0} icon with mip levels in {1} seconds", baseName, Time.realtimeSinceStartup - startTime)); - InternalEditorUtility.RepaintAllViews(); + GenerateIconWithMipLevels(assetPath, null, null); } // Refresh just one icon with provided mip levels diff --git a/Editor/Mono/Graphics/ShaderCompilerData.cs b/Editor/Mono/Graphics/ShaderCompilerData.cs index 529cc33f35..2cd0095c38 100644 --- a/Editor/Mono/Graphics/ShaderCompilerData.cs +++ b/Editor/Mono/Graphics/ShaderCompilerData.cs @@ -113,6 +113,9 @@ public enum ShaderType Fragment = 2, Geometry = 3, Hull = 4, - Domain = 5 + Domain = 5, + Surface = 6, + RayTracing = 7, + Count = 7 } } diff --git a/Editor/Mono/Grids/EditorSnap.cs b/Editor/Mono/Grids/EditorSnap.cs new file mode 100644 index 0000000000..61c16c3164 --- /dev/null +++ b/Editor/Mono/Grids/EditorSnap.cs @@ -0,0 +1,111 @@ +// 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 +{ + [FilePath("Library/EditorSnapSettings.asset", FilePathAttribute.Location.ProjectFolder)] + class EditorSnapSettingsData : ScriptableSingleton + { + [SerializeField] + bool m_SnapEnabled; + + [SerializeField] + SnapSettings m_SnapSettings = new SnapSettings(); + + internal bool snapEnabled + { + get { return m_SnapEnabled; } + set { m_SnapEnabled = value; } + } + + internal SnapSettings snapSettings + { + get { return m_SnapSettings; } + set { m_SnapSettings = value; } + } + + void OnDisable() + { + Save(); + } + + internal void Save() + { + Save(true); + } + } + + public static class EditorSnapSettings + { + static EditorSnapSettingsData instance + { + get { return EditorSnapSettingsData.instance; } + } + + // Is snapping toggled as `on` in the grid toolbar + public static bool enabled + { + get { return instance.snapEnabled; } + set { instance.snapEnabled = value; } + } + + // Is snapping active (either through shortcut key or enabled) + public static bool active + { + get + { + return Event.current == null + ? instance.snapEnabled + : EditorGUI.actionKey ? !instance.snapEnabled : instance.snapEnabled; + } + } + + public static bool preferGrid + { + get { return instance.snapSettings.preferGrid; } + set { instance.snapSettings.preferGrid = value; } + } + + public static Vector3 move + { + get { return instance.snapSettings.snapValue; } + set { instance.snapSettings.snapValue = value; } + } + + public static float rotate + { + get { return instance.snapSettings.rotation; } + set { instance.snapSettings.rotation = value; } + } + + public static float scale + { + get { return instance.snapSettings.scale; } + set { instance.snapSettings.scale = value; } + } + + public static void ResetSnapSettings() + { + instance.snapSettings = new SnapSettings(); + } + + internal static Vector3Int snapMultiplier + { + get { return instance.snapSettings.snapMultiplier; } + set { instance.snapSettings.snapMultiplier = value; } + } + + internal static void ResetMultiplier() + { + instance.snapSettings.ResetMultiplier(); + } + + internal static void Save() + { + instance.Save(); + } + } +} diff --git a/Editor/Mono/Grids/GridSettingsWindow.cs b/Editor/Mono/Grids/GridSettingsWindow.cs new file mode 100644 index 0000000000..97d6001aea --- /dev/null +++ b/Editor/Mono/Grids/GridSettingsWindow.cs @@ -0,0 +1,109 @@ +// 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.Snap +{ + internal sealed class GridSettingsWindow : PopupWindowContent + { + static class Contents + { + public static readonly GUIContent axisHeader = EditorGUIUtility.TrTextContent("Grid Axis"); + public static readonly GUIContent axisX = EditorGUIUtility.TrTextContent("X"); + public static readonly GUIContent axisY = EditorGUIUtility.TrTextContent("Y"); + public static readonly GUIContent axisZ = EditorGUIUtility.TrTextContent("Z"); + + public static readonly GUIContent settingsHeader = EditorGUIUtility.TrTextContent("Grid Settings"); + public static readonly GUIContent opacitySlider = EditorGUIUtility.TrTextContent("Opacity"); + } + + static class Styles + { + public static readonly GUIStyle menuItem = "MenuItem"; + public static readonly GUIStyle header = EditorStyles.boldLabel; + public static readonly GUIStyle separator = "sv_iconselector_sep"; + } + + const float k_WindowWidth = 190; + const float k_WindowHeight = 120; + readonly SceneView m_SceneView; + + public GridSettingsWindow(SceneView sceneView) + { + m_SceneView = sceneView; + } + + public override Vector2 GetWindowSize() + { + return new Vector2(k_WindowWidth, k_WindowHeight); + } + + public override void OnGUI(Rect rect) + { + Draw(); + + // Use mouse move so we get hover state correctly in the menu item rows + if (Event.current.type == EventType.MouseMove) + Event.current.Use(); + + // Escape closes the window + if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Escape) + { + editorWindow.Close(); + GUIUtility.ExitGUI(); + } + } + + void Draw() + { + EditorGUI.BeginChangeCheck(); + DoGridAxes(); + DoSeparator(); + DoGridSettings(); + if (EditorGUI.EndChangeCheck()) + { + SceneView.RepaintAll(); + } + } + + void DoGridAxes() + { + GUILayout.Label(Contents.axisHeader, Styles.header); + + var axis = m_SceneView.sceneViewGrids.gridAxis; + + if (DrawListElement(Contents.axisX, axis == SceneViewGrid.GridRenderAxis.X)) + m_SceneView.sceneViewGrids.gridAxis = SceneViewGrid.GridRenderAxis.X; + + if (DrawListElement(Contents.axisY, axis == SceneViewGrid.GridRenderAxis.Y)) + m_SceneView.sceneViewGrids.gridAxis = SceneViewGrid.GridRenderAxis.Y; + + if (DrawListElement(Contents.axisZ, axis == SceneViewGrid.GridRenderAxis.Z)) + m_SceneView.sceneViewGrids.gridAxis = SceneViewGrid.GridRenderAxis.Z; + } + + void DoGridSettings() + { + GUILayout.Label(Contents.settingsHeader, Styles.header); + + EditorGUIUtility.labelWidth = EditorGUI.CalcPrefixLabelWidth(Contents.opacitySlider, EditorStyles.label); + m_SceneView.sceneViewGrids.gridOpacity = EditorGUILayout.Slider(Contents.opacitySlider, m_SceneView.sceneViewGrids.gridOpacity, 0, 1); + EditorGUIUtility.labelWidth = 0; + } + + void DoSeparator() + { + EditorGUILayout.Space(EditorGUIUtility.standardVerticalSpacing); + GUILayout.Label(GUIContent.none, Styles.separator); + } + + static bool DrawListElement(GUIContent content, bool selected) + { + EditorGUI.BeginChangeCheck(); + GUILayout.Toggle(selected, content, Styles.menuItem); + return EditorGUI.EndChangeCheck(); + } + } +} diff --git a/Editor/Mono/Grids/GridShortcuts.cs b/Editor/Mono/Grids/GridShortcuts.cs new file mode 100644 index 0000000000..7175dded8c --- /dev/null +++ b/Editor/Mono/Grids/GridShortcuts.cs @@ -0,0 +1,119 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using UnityEditor.ShortcutManagement; +using UnityEngine; + +namespace UnityEditor.Snap +{ + internal static class Shortcuts + { + [Shortcut("Snap/Toggle Snap", typeof(SceneView), KeyCode.Backslash)] + internal static void ToggleSnap() + { + EditorSnapSettings.enabled = !EditorSnapSettings.enabled; + } + + [Shortcut("Grid/Increase Grid Size", typeof(SceneView), KeyCode.RightBracket, ShortcutModifiers.Action)] + internal static void IncreaseGridSize() + { + if (!EditorSnapSettings.enabled) + return; + var val = EditorSnapSettings.snapMultiplier; + if (val.x < int.MaxValue / 2) + val.x *= 2; + if (val.y < int.MaxValue / 2) + val.y *= 2; + if (val.z < int.MaxValue / 2) + val.z *= 2; + EditorSnapSettings.snapMultiplier = val; + } + + [Shortcut("Grid/Decrease Grid Size", typeof(SceneView), KeyCode.LeftBracket, ShortcutModifiers.Action)] + internal static void DecreaseGridSize() + { + if (!EditorSnapSettings.enabled) + return; + + var val = EditorSnapSettings.snapMultiplier; + if (val.x > 1) + val.x /= 2; + if (val.y > 1) + val.y /= 2; + if (val.z > 1) + val.z /= 2; + EditorSnapSettings.snapMultiplier = val; + } + + [Shortcut("Grid/Reset Grid", typeof(SceneView))] + internal static void ResetGrid() + { + MenuNudgePerspectiveReset(); + ResetGridSize(); + } + + internal static void ResetGridSize() + { + if (!EditorSnapSettings.enabled) + return; + + EditorSnapSettings.ResetMultiplier(); + } + + [Shortcut("Grid/Nudge Grid Backward", typeof(SceneView), KeyCode.LeftBracket, ShortcutModifiers.Shift)] + internal static void MenuNudgePerspectiveBackward() + { + SceneView sv = SceneView.lastActiveSceneView; + SceneViewGrid.Grid grid = sv.sceneViewGrids.activeGrid; + SceneViewGrid.GridRenderAxis axis = sv.sceneViewGrids.gridAxis; + Vector3 v = sv.sceneViewGrids.GetPivot(axis); + switch (axis) + { + case SceneViewGrid.GridRenderAxis.X: + v -= Vector3.right * EditorSnapSettings.move.x; + break; + case SceneViewGrid.GridRenderAxis.Y: + v -= Vector3.up * EditorSnapSettings.move.y; + break; + case SceneViewGrid.GridRenderAxis.Z: + v -= Vector3.forward * EditorSnapSettings.move.z; + break; + } + + sv.sceneViewGrids.SetPivot(axis, v); + sv.Repaint(); + } + + [Shortcut("Grid/Nudge Grid Forward", typeof(SceneView), KeyCode.RightBracket, ShortcutModifiers.Shift)] + internal static void MenuNudgePerspectiveForward() + { + SceneView sv = SceneView.lastActiveSceneView; + SceneViewGrid.Grid grid = sv.sceneViewGrids.activeGrid; + SceneViewGrid.GridRenderAxis axis = sv.sceneViewGrids.gridAxis; + Vector3 v = sv.sceneViewGrids.GetPivot(axis); + switch (axis) + { + case SceneViewGrid.GridRenderAxis.X: + v += Vector3.right * EditorSnapSettings.move.x; + break; + case SceneViewGrid.GridRenderAxis.Y: + v += Vector3.up * EditorSnapSettings.move.y; + break; + case SceneViewGrid.GridRenderAxis.Z: + v += Vector3.forward * EditorSnapSettings.move.z; + break; + } + + sv.sceneViewGrids.SetPivot(axis, v); + sv.Repaint(); + } + + internal static void MenuNudgePerspectiveReset() + { + SceneView sv = SceneView.lastActiveSceneView; + sv.ResetGrid(); + sv.Repaint(); + } + } +} diff --git a/Editor/Mono/Grids/SnapSettings.cs b/Editor/Mono/Grids/SnapSettings.cs new file mode 100644 index 0000000000..7f78722d3a --- /dev/null +++ b/Editor/Mono/Grids/SnapSettings.cs @@ -0,0 +1,83 @@ +// 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; + +namespace UnityEditor +{ + [Serializable] + class SnapSettings + { + const int k_DefaultSnapMultiplier = 2048; + const float k_DefaultSnapValue = 1f; + const float k_DefaultRotation = 15f; + const float k_DefaultScale = 1f; + + // If handle movement is aligned with grid coordinates, snap to grid instead of incremental from handle origin + [SerializeField] + bool m_PreferGrid; + + [SerializeField] + Vector3 m_SnapValue = new Vector3(k_DefaultSnapValue, k_DefaultSnapValue, k_DefaultSnapValue); + + [SerializeField] + Vector3Int m_SnapMultiplier = new Vector3Int(k_DefaultSnapMultiplier, k_DefaultSnapMultiplier, k_DefaultSnapMultiplier); + + [SerializeField] + float m_Rotation = k_DefaultRotation; + + [SerializeField] + float m_Scale = k_DefaultScale; + + internal Vector3 snapValue + { + get { return SnapValueInUnityUnits(); } + set { m_SnapValue = value; snapMultiplier = new Vector3Int(k_DefaultSnapMultiplier, k_DefaultSnapMultiplier, k_DefaultSnapMultiplier); } + } + + // When moving a handle along a cardinal direction, handles will snap to the nearest grid point instead of + // increments from the handle origin. + internal bool preferGrid + { + get { return m_PreferGrid; } + set { m_PreferGrid = value; } + } + + internal Vector3Int snapMultiplier + { + get { return m_SnapMultiplier; } + set { m_SnapMultiplier = value; } + } + + internal void ResetMultiplier() + { + m_SnapMultiplier = new Vector3Int(k_DefaultSnapMultiplier, k_DefaultSnapMultiplier, k_DefaultSnapMultiplier); + } + + public float rotation + { + get { return m_Rotation; } + set { m_Rotation = value; } + } + + public float scale + { + get { return m_Scale; } + set { m_Scale = value; } + } + + Vector3Int SnapMultiplierFrac() + { + var val = 1.0f / (float)k_DefaultSnapMultiplier; + return new Vector3Int((int)(m_SnapMultiplier.x * val), (int)(m_SnapMultiplier.y * val), (int)(m_SnapMultiplier.z * val)); + } + + Vector3 SnapValueInUnityUnits() + { + var frac = SnapMultiplierFrac(); + return new Vector3(m_SnapValue.x * frac.x, m_SnapValue.y * frac.y, m_SnapValue.z * frac.z); + } + } +} diff --git a/Editor/Mono/Grids/SnapSettingsWindow.cs b/Editor/Mono/Grids/SnapSettingsWindow.cs new file mode 100644 index 0000000000..2083f9c90f --- /dev/null +++ b/Editor/Mono/Grids/SnapSettingsWindow.cs @@ -0,0 +1,242 @@ +// 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 +{ + sealed class SnapSettingsWindow : PopupWindowContent + { + static class Contents + { + public static readonly GUIContent snapSettings = EditorGUIUtility.TrTextContent("Snap Settings"); + public static readonly GUIContent moveValue = EditorGUIUtility.TrTextContent("Move", "Snap value for the Move tool"); + public static readonly GUIContent moveX = EditorGUIUtility.TrTextContent("X", "X snap value"); + public static readonly GUIContent moveY = EditorGUIUtility.TrTextContent("Y", "Y snap value"); + public static readonly GUIContent moveZ = EditorGUIUtility.TrTextContent("Z", "Z snap value"); + public static readonly GUIContent rotateValue = EditorGUIUtility.TrTextContent("Rotate", "Snap value for the Rotate tool"); + public static readonly GUIContent scaleValue = EditorGUIUtility.TrTextContent("Scale", "Snap value for the Scale tool"); + public static readonly GUIContent pushToGrid = EditorGUIUtility.TrIconContent("SceneViewPushToGrid", "Snaps selected object to the grid"); + public static readonly GUIContent pushX = EditorGUIUtility.TrIconContent("SceneViewPushToGrid", "Snaps selected object to the grid on the X axis"); + public static readonly GUIContent pushY = EditorGUIUtility.TrIconContent("SceneViewPushToGrid", "Snaps selected object to the grid on the Y axis"); + public static readonly GUIContent pushZ = EditorGUIUtility.TrIconContent("SceneViewPushToGrid", "Snaps selected object to the grid on the Z axis"); + public static readonly GUIContent reset = EditorGUIUtility.TrTextContent("Reset"); + public static readonly GUIContent preferGrid = EditorGUIUtility.TrTextContent("Prefer Grid", "When moving a handle along a cardinal direction, handles will snap to the nearest grid point instead of increments from the handle origin."); + } + + static class Styles + { + public static readonly GUIStyle separator = "sv_iconselector_sep"; + public static readonly GUIStyle header = EditorStyles.boldLabel; + public static readonly GUIStyle button = new GUIStyle(GUI.skin.button) + { + padding = new RectOffset(2, 2, 2, 2), + }; + } + + const float k_LabelWidth = 80; + const float k_WindowWidth = 200 + k_LabelWidth; + readonly float k_WindowHeight = EditorGUIUtility.singleLineHeight * 10 + 5; + readonly float k_PushToGridIconWidth = EditorGUIUtility.singleLineHeight; + readonly float k_SettingsIconSize = EditorGUIUtility.singleLineHeight; + + static bool snapValueLinked + { + get { return EditorPrefs.GetBool("SnapSettingsWindow.snapValueLinked", true); } + set { EditorPrefs.SetBool("SnapSettingsWindow.snapValueLinked", value); } + } + + public override Vector2 GetWindowSize() + { + return new Vector2(k_WindowWidth, k_WindowHeight); + } + + public override void OnGUI(Rect rect) + { + DrawTitleSettingsButton(rect); + Draw(); + + // Use mouse move so we get hover state correctly in the menu item rows + if (Event.current.type == EventType.MouseMove) + Event.current.Use(); + + // Escape closes the window + if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Escape) + { + editorWindow.Close(); + GUIUtility.ExitGUI(); + } + } + + void Draw() + { + EditorGUIUtility.labelWidth = k_LabelWidth; + + GUILayout.Label(Contents.snapSettings, Styles.header); + + EditorGUI.BeginChangeCheck(); + + DrawMoveValuesFields(); + + DoSeparator(); + + EditorSnapSettings.rotate = EditorGUILayout.FloatField(Contents.rotateValue, EditorSnapSettings.rotate); + + EditorSnapSettings.scale = EditorGUILayout.FloatField(Contents.scaleValue, EditorSnapSettings.scale); + + if (EditorGUI.EndChangeCheck()) + EditorSnapSettings.Save(); + + EditorGUIUtility.labelWidth = 0; + } + + void DoSeparator() + { + GUILayout.Space(EditorGUIUtility.standardVerticalSpacing); + GUILayout.Label(GUIContent.none, Styles.separator); + GUILayout.Space(EditorGUIUtility.standardVerticalSpacing); + } + + void DrawMoveValuesFields() + { + EditorSnapSettings.preferGrid = EditorGUILayout.Toggle(Contents.preferGrid, EditorSnapSettings.preferGrid); + + var v = EditorSnapSettings.move; + + using (new EditorGUILayout.HorizontalScope()) + { + EditorGUI.BeginChangeCheck(); + var linked = snapValueLinked; + var newValue = DoFloatFieldWithLink(Contents.moveValue, v.x, ref linked); + if (EditorGUI.EndChangeCheck()) + { + snapValueLinked = linked; + EditorSnapSettings.move = new Vector3(newValue, newValue, newValue); + } + + if (GUILayout.Button(Contents.pushToGrid, Styles.button, GUILayout.Width(k_PushToGridIconWidth))) + { + var selections = Selection.transforms; + Undo.RecordObjects(selections, L10n.Tr("Snap to Grid")); + Handles.SnapToGrid(selections); + } + } + + ++EditorGUI.indentLevel; + + using (new EditorGUILayout.HorizontalScope()) + { + using (new EditorGUI.DisabledScope(snapValueLinked)) + { + var value = EditorSnapSettings.move; + EditorGUI.BeginChangeCheck(); + using (new EditorGUI.DisabledScope(snapValueLinked)) + { + var newValue = EditorGUILayout.FloatField(Contents.moveX, value.x); + + if (EditorGUI.EndChangeCheck()) + { + EditorSnapSettings.move = new Vector3(newValue, value.y, value.z); + } + } + } + + if (GUILayout.Button(Contents.pushX, Styles.button, GUILayout.Width(k_PushToGridIconWidth))) + { + var selections = Selection.transforms; + Undo.RecordObjects(selections, L10n.Tr("Snap to Grid")); + Handles.SnapToGrid(selections, SnapAxis.X); + } + } + + using (new EditorGUILayout.HorizontalScope()) + { + using (new EditorGUI.DisabledScope(snapValueLinked)) + { + var value = EditorSnapSettings.move; + EditorGUI.BeginChangeCheck(); + var newValue = EditorGUILayout.FloatField(Contents.moveY, value.y); + if (EditorGUI.EndChangeCheck()) + { + EditorSnapSettings.move = new Vector3(value.x, newValue, value.z); + } + } + + if (GUILayout.Button(Contents.pushY, Styles.button, GUILayout.Width(k_PushToGridIconWidth))) + { + var selections = Selection.transforms; + Undo.RecordObjects(selections, L10n.Tr("Snap to Grid")); + Handles.SnapToGrid(selections, SnapAxis.Y); + } + } + + using (new EditorGUILayout.HorizontalScope()) + { + using (new EditorGUI.DisabledScope(snapValueLinked)) + { + var value = EditorSnapSettings.move; + EditorGUI.BeginChangeCheck(); + var newValue = EditorGUILayout.FloatField(Contents.moveZ, value.z); + if (EditorGUI.EndChangeCheck()) + { + EditorSnapSettings.move = new Vector3(value.x, value.y, newValue); + } + } + + if (GUILayout.Button(Contents.pushZ, Styles.button, GUILayout.Width(k_PushToGridIconWidth))) + { + var selections = Selection.transforms; + Undo.RecordObjects(selections, L10n.Tr("Snap to Grid")); + Handles.SnapToGrid(selections, SnapAxis.Z); + } + } + --EditorGUI.indentLevel; + } + + public static bool IsMoveSnapValueMixed() + { + if (snapValueLinked) + return false; + + return EditorSnapSettings.move.x != EditorSnapSettings.move.y || EditorSnapSettings.move.y != EditorSnapSettings.move.z; + } + + float DoFloatFieldWithLink(GUIContent content, float value, ref bool linkToggle) + { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PrefixLabel(content); + + float result; + using (new EditorGUI.DisabledScope(!linkToggle)) + { + EditorGUI.showMixedValue = IsMoveSnapValueMixed(); + result = EditorGUILayout.FloatField(value); + EditorGUI.showMixedValue = false; + } + + linkToggle = EditorGUILayout.Toggle(linkToggle, GUILayout.Width(15)); + EditorGUILayout.EndHorizontal(); + + return result; + } + + void DrawTitleSettingsButton(Rect rect) + { + var settingsRect = rect; + settingsRect.x = settingsRect.xMax - k_SettingsIconSize; + settingsRect.y = 0; + settingsRect.width = settingsRect.height = k_SettingsIconSize; + + if (GUI.Button(settingsRect, EditorGUI.GUIContents.titleSettingsIcon, EditorStyles.iconButton)) + ShowContextMenu(); + } + + void ShowContextMenu() + { + GenericMenu menu = new GenericMenu(); + menu.AddItem(Contents.reset, false, EditorSnapSettings.ResetSnapSettings); + menu.ShowAsContext(); + } + } +} diff --git a/Editor/Mono/Handles.cs b/Editor/Mono/Handles.cs index 897cb7b366..2afcfafcf2 100644 --- a/Editor/Mono/Handles.cs +++ b/Editor/Mono/Handles.cs @@ -13,12 +13,10 @@ namespace UnityEditor [StructLayout(LayoutKind.Sequential)] struct DrawGridParameters { - public Vector3 pivot; - public Color color; - public float size; - public float alphaX; - public float alphaY; - public float alphaZ; + public int gridID; + public Vector3 pivot; + public Color color; + public Vector2 size; } public sealed partial class Handles @@ -54,7 +52,6 @@ public sealed partial class Handles internal static Color s_ColliderHandleColorDisabled = new Color(84, 200f, 77f, 140f) / 255; internal static Color s_BoundingBoxHandleColor = new Color(255, 255, 255, 150) / 255; - const int kMaxDottedLineVertices = 1000; static GUIContent s_Static = EditorGUIUtility.TrTextContent("Static"); internal static int s_SliderHash = "SliderHash".GetHashCode(); @@ -139,16 +136,6 @@ static Mesh cylinderMesh } } - static Mesh quadMesh - { - get - { - if (s_QuadMesh == null) - Init(); - return s_QuadMesh; - } - } - static Mesh sphereMesh { get @@ -345,11 +332,11 @@ public static void DrawWireCube(Vector3 center, Vector3 size) public static bool ShouldRenderGizmos() { - GameView gv = GameView.GetRenderingGameView(); + var preview = PreviewEditorWindow.GetRenderingPreview(); SceneView sv = SceneView.currentDrawingSceneView; - if (gv != null) - return gv.IsShowingGizmos(); + if (preview != null) + return preview.IsShowingGizmos(); if (sv != null) return sv.drawGizmos; @@ -848,14 +835,41 @@ internal static void SetupIgnoreRaySnapObjects() HandleUtility.ignoreRaySnapObjects = Selection.GetTransforms(SelectionMode.Editable | SelectionMode.Deep); } - //rounds the value ''val'' to the closest multiple of ''snap'' (snap can only be posiive) - public static float SnapValue(float val, float snap) + // If snapping is active, return a new value rounded to the nearest increment of snap. + public static float SnapValue(float value, float snap) + { + if (EditorSnapSettings.active) + return Snapping.Snap(value, snap); + return value; + } + + // If snapping is active, return a new value rounded to the nearest increment of snap. + public static Vector2 SnapValue(Vector2 value, Vector2 snap) { - if (EditorGUI.actionKey && snap > 0) + if (EditorSnapSettings.active) + return Snapping.Snap(value, snap); + return value; + } + + // If snapping is active, return a new value rounded to the nearest increment of snap. + public static Vector3 SnapValue(Vector3 value, Vector3 snap) + { + if (EditorSnapSettings.active) + return Snapping.Snap(value, snap); + return value; + } + + // Snap all transform positions to the grid + public static void SnapToGrid(Transform[] transforms, SnapAxis axis = SnapAxis.All) + { + if (transforms != null && transforms.Length > 0) { - return Mathf.Round(val / snap) * snap; + foreach (var t in transforms) + { + if (t != null) + t.position = Snapping.Snap(t.position, Vector3.Scale(EditorSnapSettings.move, new SnapAxisFilter(axis))); + } } - return val; } // The camera used for deciding where 3D handles end up @@ -1297,10 +1311,10 @@ internal static Rect GetCameraRect(Rect position) return cameraRect; } - // Get the size of the main game view window + // Get the size of the main preview window public static Vector2 GetMainGameViewSize() { - return GameView.GetMainGameViewTargetSize(); + return PreviewEditorWindow.GetMainPreviewTargetSize(); } // Clears the camera. diff --git a/Editor/Mono/ImportSettings/SpeedTreeImporterModelEditor.cs b/Editor/Mono/ImportSettings/SpeedTreeImporterModelEditor.cs index 03d2b6fa32..abfa2245b5 100644 --- a/Editor/Mono/ImportSettings/SpeedTreeImporterModelEditor.cs +++ b/Editor/Mono/ImportSettings/SpeedTreeImporterModelEditor.cs @@ -8,7 +8,6 @@ using System.Linq; using UnityEditor.AnimatedValues; using UnityEditor.Experimental.AssetImporters; -using UnityEditor.VersionControl; using UnityEngine; namespace UnityEditor @@ -101,23 +100,6 @@ internal override void OnDisable() m_ShowCrossFadeWidthOptions.valueChanged.RemoveListener(Repaint); } - private void GenerateMaterials() - { - string[] matFolders = importers.Select(im => im.materialFolderPath).ToArray(); - string[] guids = AssetDatabase.FindAssets("t:Material", matFolders); - string[] paths = guids.Select(guid => AssetDatabase.GUIDToAssetPath(guid)).ToArray(); - - bool doGenerate = true; - if (paths.Length > 0) - doGenerate = Provider.PromptAndCheckoutIfNeeded(paths, String.Format("Materials will be checked out in:\n{0}", String.Join("\n", matFolders))); - - if (doGenerate) - { - foreach (var importer in importers) - importer.GenerateMaterials(); - } - } - internal List GetLODInfoArray(Rect area) { int lodCount = m_LODSettings.arraySize; diff --git a/Editor/Mono/ImportSettings/TextureImportPlatformSettings.cs b/Editor/Mono/ImportSettings/TextureImportPlatformSettings.cs index 3b250e4945..ba817996af 100644 --- a/Editor/Mono/ImportSettings/TextureImportPlatformSettings.cs +++ b/Editor/Mono/ImportSettings/TextureImportPlatformSettings.cs @@ -2,15 +2,8 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License -using UnityEditor.AnimatedValues; -using UnityEditor.Modules; using UnityEngine; -using System.Collections; -using System.Collections.Generic; using System.Linq; -using System; -using UnityEngine.Assertions; -using Object = UnityEngine.Object; namespace UnityEditor { @@ -373,13 +366,6 @@ public void Sync() } } - private bool GetOverridden(TextureImporter importer) - { - if (!m_OverriddenIsDifferent) - return overridden; - return importer.GetPlatformTextureSettings(name).overridden; - } - public void Apply() { for (int i = 0; i < importers.Length; i++) diff --git a/Editor/Mono/Inspector/AdvancedDropdown/DataSources/SimpleDataSource.cs b/Editor/Mono/Inspector/AdvancedDropdown/DataSources/SimpleDataSource.cs index b7443532d2..00f6a05c03 100644 --- a/Editor/Mono/Inspector/AdvancedDropdown/DataSources/SimpleDataSource.cs +++ b/Editor/Mono/Inspector/AdvancedDropdown/DataSources/SimpleDataSource.cs @@ -16,7 +16,9 @@ internal GUIContent[] displayedOptions } private static int m_SelectedIndex; +#pragma warning disable 0649 private AdvancedDropdownState m_State; +#pragma warning restore 0649 internal int selectedIndex { diff --git a/Editor/Mono/Inspector/AssemblyDefinitionImporterInspector.cs b/Editor/Mono/Inspector/AssemblyDefinitionImporterInspector.cs index 05a71a33a4..1430a91d6f 100644 --- a/Editor/Mono/Inspector/AssemblyDefinitionImporterInspector.cs +++ b/Editor/Mono/Inspector/AssemblyDefinitionImporterInspector.cs @@ -124,6 +124,7 @@ public string path SerializedProperty m_CompatibleWithAnyPlatform; SerializedProperty m_PlatformCompatibility; + string[] m_Defines; Exception initializeException; public override bool showImportedObject { get { return false; } } @@ -131,9 +132,11 @@ public string path public override void OnEnable() { base.OnEnable(); + m_AssemblyName = extraDataSerializedObject.FindProperty("assemblyName"); + m_Defines = CompilationPipeline.GetDefinesFromAssemblyName(m_AssemblyName.stringValue); + InitializeReorderableLists(); m_SemVersionRanges = new SemVersionRangesFactory(); - m_AssemblyName = extraDataSerializedObject.FindProperty("assemblyName"); m_AllowUnsafeCode = extraDataSerializedObject.FindProperty("allowUnsafeCode"); m_UseGUIDs = extraDataSerializedObject.FindProperty("useGUIDs"); m_AutoReferenced = extraDataSerializedObject.FindProperty("autoReferenced"); @@ -187,24 +190,24 @@ public override void OnInspectorGUI() EditorGUILayout.PropertyField(m_UseGUIDs, Styles.useGUIDs); EditorGUILayout.EndVertical(); + m_ReferencesList.DoLayoutList(); + if (extraDataTargets.Any(data => ((AssemblyDefinitionState)data).references != null && ((AssemblyDefinitionState)data).references.Any(x => x.asset == null))) { EditorGUILayout.HelpBox("The grayed out assembly references are missing and will not be referenced during compilation.", MessageType.Info); } - m_ReferencesList.DoLayoutList(); - if (m_OverrideReferences.boolValue && !m_OverrideReferences.hasMultipleDifferentValues) { GUILayout.Label(Styles.precompiledReferences, EditorStyles.boldLabel); + UpdatePrecompiledReferenceListEntry(); + m_PrecompiledReferencesList.DoLayoutList(); + if (extraDataTargets.Any(data => ((AssemblyDefinitionState)data).precompiledReferences.Any(x => string.IsNullOrEmpty(x.path) && !string.IsNullOrEmpty(x.name)))) { EditorGUILayout.HelpBox("The grayed out assembly references are missing and will not be referenced during compilation.", MessageType.Info); } - - UpdatePrecompiledReferenceListEntry(); - m_PrecompiledReferencesList.DoLayoutList(); } @@ -370,15 +373,25 @@ private void DrawDefineConstraintListElement(Rect rect, int index, bool isactive rect.height -= EditorGUIUtility.standardVerticalSpacing; + var textFieldRect = new Rect(rect.x, rect.y + 1, rect.width - ReorderableList.Defaults.dragHandleWidth, rect.height); + + var validRect = new Rect(rect.width + ReorderableList.Defaults.dragHandleWidth + 1, rect.y + 1, ReorderableList.Defaults.dragHandleWidth, rect.height); + string noValue = L10n.Tr("(Missing)"); var label = string.IsNullOrEmpty(defineConstraint.stringValue) ? noValue : defineConstraint.stringValue; - bool mixed = defineConstraint.hasMultipleDifferentValues; EditorGUI.showMixedValue = mixed; - var textFieldValue = EditorGUI.TextField(rect, mixed ? L10n.Tr("(Multiple Values)") : label); + var textFieldValue = EditorGUI.TextField(textFieldRect, mixed ? L10n.Tr("(Multiple Values)") : label); EditorGUI.showMixedValue = false; + if (m_Defines != null) + { + EditorGUI.BeginDisabled(true); + EditorGUI.Toggle(validRect, DefineConstraintsHelper.IsDefineConstraintValid(m_Defines, defineConstraint.stringValue)); + EditorGUI.EndDisabled(); + } + if (!string.IsNullOrEmpty(textFieldValue) && textFieldValue != noValue) { defineConstraint.stringValue = textFieldValue; @@ -418,7 +431,7 @@ private void DrawVersionDefineListElement(Rect rect, int index, bool isactive, b nameProp.stringValue = assetPathsMetaData[popupIndex]; elementRect.y += EditorGUIUtility.singleLineHeight; - defineProp.stringValue = EditorGUI.TextField(elementRect, GUIContent.Temp("Define", "Specify the name you want this define to have. This define is only set if the expression below returns true."), defineProp.stringValue); + defineProp.stringValue = EditorGUI.TextField(elementRect, GUIContent.Temp("Define", "Specify the name you want this define to have. This define is only set if the expression below returns true."), defineProp.stringValue); elementRect.y += EditorGUIUtility.singleLineHeight; expressionProp.stringValue = EditorGUI.TextField(elementRect, GUIContent.Temp("Expression", "Specify the semantic version of your chosen module or package. You must use mathematical interval notation."), expressionProp.stringValue); @@ -584,9 +597,9 @@ static void LoadAssemblyDefintionState(AssemblyDefinitionState state, string pat if (data.defineConstraints != null) { - foreach (var defineConstaint in data.defineConstraints) + foreach (var defineConstraint in data.defineConstraints) { - var symbolName = defineConstaint.StartsWith(DefineConstraintsHelper.Not) ? defineConstaint.Substring(1) : defineConstaint; + var symbolName = defineConstraint.StartsWith(DefineConstraintsHelper.Not) ? defineConstraint.Substring(1) : defineConstraint; if (!SymbolNameRestrictions.IsValid(symbolName)) { var exception = new AssemblyDefinitionException($"Invalid define constraint {symbolName}", path); @@ -596,7 +609,7 @@ static void LoadAssemblyDefintionState(AssemblyDefinitionState state, string pat { state.defineConstraints.Add(new DefineConstraint { - name = defineConstaint, + name = defineConstraint, }); } } diff --git a/Editor/Mono/Inspector/Avatar/AvatarEditor.cs b/Editor/Mono/Inspector/Avatar/AvatarEditor.cs index 188c8582ce..8276b2f6bd 100644 --- a/Editor/Mono/Inspector/Avatar/AvatarEditor.cs +++ b/Editor/Mono/Inspector/Avatar/AvatarEditor.cs @@ -5,9 +5,7 @@ using UnityEngine; using UnityEditor.SceneManagement; using System; -using System.Collections; using System.Collections.Generic; -using UnityEditorInternal; using UnityEngine.SceneManagement; namespace UnityEditor @@ -39,7 +37,7 @@ public void OnPostprocessModel(GameObject go) } */ - //[MenuItem ("Mecanim/Write All Assets")] + /*[MenuItem ("Mecanim/Write All Assets")] static void DoWriteAllAssets() { UnityEngine.Object[] objects = Resources.FindObjectsOfTypeAll(typeof(UnityEngine.Object)); @@ -49,7 +47,7 @@ static void DoWriteAllAssets() EditorUtility.SetDirty(asset); } AssetDatabase.SaveAssets(); - } + }*/ protected AvatarEditor m_Inspector; protected GameObject gameObject { get { return m_Inspector.m_GameObject; } } @@ -257,7 +255,6 @@ protected AvatarSubEditor editor const int sMappingTab = 0; const int sMuscleTab = 1; - const int sDefaultTab = sMappingTab; public GameObject prefab { diff --git a/Editor/Mono/Inspector/BoxColliderEditor.cs b/Editor/Mono/Inspector/BoxColliderEditor.cs index 8abf235907..501b5d9764 100644 --- a/Editor/Mono/Inspector/BoxColliderEditor.cs +++ b/Editor/Mono/Inspector/BoxColliderEditor.cs @@ -2,18 +2,39 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License +using UnityEditor.EditorTools; using UnityEditor.IMGUI.Controls; using UnityEngine; namespace UnityEditor { + [EditorTool("Edit Box Collider", typeof(BoxCollider))] + class BoxPrimitiveColliderTool : PrimitiveColliderTool + { + readonly BoxBoundsHandle m_BoundsHandle = new BoxBoundsHandle(); + protected override PrimitiveBoundsHandle boundsHandle { get { return m_BoundsHandle; } } + + protected override void CopyColliderPropertiesToHandle(BoxCollider collider) + { + m_BoundsHandle.center = TransformColliderCenterToHandleSpace(collider.transform, collider.center); + m_BoundsHandle.size = Vector3.Scale(collider.size, collider.transform.lossyScale); + } + + protected override void CopyHandlePropertiesToCollider(BoxCollider collider) + { + collider.center = TransformHandleCenterToColliderSpace(collider.transform, m_BoundsHandle.center); + Vector3 size = Vector3.Scale(m_BoundsHandle.size, InvertScaleVector(collider.transform.lossyScale)); + size = new Vector3(Mathf.Abs(size.x), Mathf.Abs(size.y), Mathf.Abs(size.z)); + collider.size = size; + } + } + [CustomEditor(typeof(BoxCollider))] [CanEditMultipleObjects] - internal class BoxColliderEditor : PrimitiveCollider3DEditor + class BoxColliderEditor : Collider3DEditorBase { SerializedProperty m_Center; 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 sizeContent = EditorGUIUtility.TrTextContent("Size", "The size of the Collider in the X, Y, Z directions."); @@ -31,7 +52,8 @@ public override void OnInspectorGUI() { serializedObject.Update(); - InspectorEditButtonGUI(); + EditorGUILayout.EditorToolbarForTarget(EditorGUIUtility.TrTempContent("Edit Collider"), target); + EditorGUILayout.PropertyField(m_IsTrigger, triggerContent); EditorGUILayout.PropertyField(m_Material, materialContent); EditorGUILayout.PropertyField(m_Center, centerContent); @@ -39,23 +61,5 @@ public override void OnInspectorGUI() serializedObject.ApplyModifiedProperties(); } - - protected override PrimitiveBoundsHandle boundsHandle { get { return m_BoundsHandle; } } - - protected override void CopyColliderPropertiesToHandle() - { - BoxCollider collider = (BoxCollider)target; - m_BoundsHandle.center = TransformColliderCenterToHandleSpace(collider.transform, collider.center); - m_BoundsHandle.size = Vector3.Scale(collider.size, collider.transform.lossyScale); - } - - protected override void CopyHandlePropertiesToCollider() - { - BoxCollider collider = (BoxCollider)target; - collider.center = TransformHandleCenterToColliderSpace(collider.transform, m_BoundsHandle.center); - Vector3 size = Vector3.Scale(m_BoundsHandle.size, InvertScaleVector(collider.transform.lossyScale)); - size = new Vector3(Mathf.Abs(size.x), Mathf.Abs(size.y), Mathf.Abs(size.z)); - collider.size = size; - } } } diff --git a/Editor/Mono/Inspector/CameraEditor.cs b/Editor/Mono/Inspector/CameraEditor.cs index d6c4626dca..948507e958 100644 --- a/Editor/Mono/Inspector/CameraEditor.cs +++ b/Editor/Mono/Inspector/CameraEditor.cs @@ -626,7 +626,7 @@ private void CommandBufferGUI() { cam.RemoveCommandBuffer(ce, cb); SceneView.RepaintAll(); - GameView.RepaintAll(); + PreviewEditorWindow.RepaintAll(); GUIUtility.ExitGUI(); } } @@ -640,7 +640,7 @@ private void CommandBufferGUI() { cam.RemoveAllCommandBuffers(); SceneView.RepaintAll(); - GameView.RepaintAll(); + PreviewEditorWindow.RepaintAll(); } } EditorGUI.indentLevel--; @@ -720,7 +720,7 @@ public virtual void OnOverlayGUI(Object target, SceneView sceneView) if (targetStage != sceneViewStage) return; - Vector2 previewSize = c.targetTexture ? new Vector2(c.targetTexture.width, c.targetTexture.height) : GameView.GetMainGameViewTargetSize(); + Vector2 previewSize = c.targetTexture ? new Vector2(c.targetTexture.width, c.targetTexture.height) : PreviewEditorWindow.GetMainPreviewTargetSize(); if (previewSize.x < 0f) { @@ -767,6 +767,7 @@ public virtual void OnOverlayGUI(Object target, SceneView sceneView) { // setup camera and render previewCamera.CopyFrom(c); + previewCamera.cameraType = CameraType.Preview; // make sure the preview camera is rendering the same stage as the SceneView is previewCamera.scene = sceneView.customScene; @@ -822,7 +823,7 @@ private RenderTexture GetPreviewTextureWithSize(int width, int height) [RequiredByNativeCode] internal static float GetGameViewAspectRatio() { - Vector2 gameViewSize = GameView.GetMainGameViewTargetSize(); + Vector2 gameViewSize = PreviewEditorWindow.GetMainPreviewTargetSize(); if (gameViewSize.x < 0f) { // Fallback to Scene View of not a valid game view size @@ -833,6 +834,12 @@ internal static float GetGameViewAspectRatio() return gameViewSize.x / gameViewSize.y; } + [RequiredByNativeCode] + internal static Vector2 GetMainPreviewSize() + { + return PreviewEditorWindow.GetMainPreviewTargetSize(); + } + // Called from C++ when we need to render a Camera's gizmo internal static void RenderGizmo(Camera camera) { @@ -849,7 +856,7 @@ public virtual void OnSceneGUI() if (!CameraEditorUtils.IsViewportRectValidToRender(c.rect)) return; - Vector2 currentMainGameViewTargetSize = GameView.GetMainGameViewTargetSize(); + Vector2 currentMainGameViewTargetSize = PreviewEditorWindow.GetMainPreviewTargetSize(); if (s_PreviousMainGameViewTargetSize != currentMainGameViewTargetSize) { // a gameView size change can affect horizontal FOV, refresh the inspector when that happens. diff --git a/Editor/Mono/Inspector/CapsuleColliderEditor.cs b/Editor/Mono/Inspector/CapsuleColliderEditor.cs index 807d8370a2..e6854b4203 100644 --- a/Editor/Mono/Inspector/CapsuleColliderEditor.cs +++ b/Editor/Mono/Inspector/CapsuleColliderEditor.cs @@ -2,59 +2,29 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License +using UnityEditor.EditorTools; using UnityEditor.IMGUI.Controls; using UnityEngine; namespace UnityEditor { - [CustomEditor(typeof(CapsuleCollider))] - [CanEditMultipleObjects] - internal class CapsuleColliderEditor : PrimitiveCollider3DEditor + [EditorTool("Edit Capsule Collider", typeof(CapsuleCollider))] + class CapsuleColliderTool : PrimitiveColliderTool { - SerializedProperty m_Center; - SerializedProperty m_Radius; - SerializedProperty m_Height; - SerializedProperty m_Direction; - - private readonly CapsuleBoundsHandle m_BoundsHandle = new CapsuleBoundsHandle(); - - public override void OnEnable() - { - base.OnEnable(); - - m_Center = serializedObject.FindProperty("m_Center"); - m_Radius = serializedObject.FindProperty("m_Radius"); - m_Height = serializedObject.FindProperty("m_Height"); - m_Direction = serializedObject.FindProperty("m_Direction"); - } - - public override void OnInspectorGUI() - { - serializedObject.Update(); - - InspectorEditButtonGUI(); - EditorGUILayout.PropertyField(m_IsTrigger); - EditorGUILayout.PropertyField(m_Material); - EditorGUILayout.PropertyField(m_Center); - EditorGUILayout.PropertyField(m_Radius); - EditorGUILayout.PropertyField(m_Height); - EditorGUILayout.PropertyField(m_Direction); - - serializedObject.ApplyModifiedProperties(); - } - + readonly CapsuleBoundsHandle m_BoundsHandle = new CapsuleBoundsHandle(); protected override PrimitiveBoundsHandle boundsHandle { get { return m_BoundsHandle; } } - protected override void CopyColliderPropertiesToHandle() + protected override void CopyColliderPropertiesToHandle(CapsuleCollider collider) { - CapsuleCollider collider = (CapsuleCollider)target; m_BoundsHandle.center = TransformColliderCenterToHandleSpace(collider.transform, collider.center); + float radiusScaleFactor; - Vector3 sizeScale = - GetCapsuleColliderHandleScale(collider.transform.lossyScale, collider.direction, out radiusScaleFactor); + Vector3 sizeScale = GetCapsuleColliderHandleScale(collider.transform.lossyScale, collider.direction, out radiusScaleFactor); + m_BoundsHandle.height = m_BoundsHandle.radius = 0f; m_BoundsHandle.height = collider.height * Mathf.Abs(sizeScale[collider.direction]); m_BoundsHandle.radius = collider.radius * radiusScaleFactor; + switch (collider.direction) { case 0: @@ -69,30 +39,30 @@ protected override void CopyColliderPropertiesToHandle() } } - protected override void CopyHandlePropertiesToCollider() + protected override void CopyHandlePropertiesToCollider(CapsuleCollider collider) { - CapsuleCollider collider = (CapsuleCollider)target; collider.center = TransformHandleCenterToColliderSpace(collider.transform, m_BoundsHandle.center); + float radiusScaleFactor; - Vector3 sizeScale = - GetCapsuleColliderHandleScale(collider.transform.lossyScale, collider.direction, out radiusScaleFactor); + Vector3 sizeScale = GetCapsuleColliderHandleScale(collider.transform.lossyScale, collider.direction, out radiusScaleFactor); sizeScale = InvertScaleVector(sizeScale); + // only apply changes to collider radius/height if scale factor from transform is non-zero if (radiusScaleFactor != 0f) collider.radius = m_BoundsHandle.radius / radiusScaleFactor; + if (sizeScale[collider.direction] != 0f) collider.height = m_BoundsHandle.height * Mathf.Abs(sizeScale[collider.direction]); } - protected override void OnSceneGUI() + public override void OnToolGUI(EditorWindow window) { - if (!target) - return; // prevent possibility that user increases height if radius scale is zero and user drags (non-moving) radius handles to exceed height extents CapsuleCollider collider = (CapsuleCollider)target; float radiusScaleFactor; GetCapsuleColliderHandleScale(collider.transform.lossyScale, collider.direction, out radiusScaleFactor); boundsHandle.axes = PrimitiveBoundsHandle.Axes.All; + if (radiusScaleFactor == 0f) { switch (collider.direction) @@ -109,23 +79,62 @@ protected override void OnSceneGUI() } } - base.OnSceneGUI(); + base.OnToolGUI(window); } - private Vector3 GetCapsuleColliderHandleScale(Vector3 lossyScale, int capsuleDirection, out float radiusScaleFactor) + static Vector3 GetCapsuleColliderHandleScale(Vector3 lossyScale, int capsuleDirection, out float radiusScaleFactor) { radiusScaleFactor = 0f; + for (int axis = 0; axis < 3; ++axis) { if (axis != capsuleDirection) radiusScaleFactor = Mathf.Max(radiusScaleFactor, Mathf.Abs(lossyScale[axis])); } + for (int axis = 0; axis < 3; ++axis) { if (axis != capsuleDirection) lossyScale[axis] = Mathf.Sign(lossyScale[axis]) * radiusScaleFactor; } + return lossyScale; } } + + [CustomEditor(typeof(CapsuleCollider))] + [CanEditMultipleObjects] + class CapsuleColliderEditor : Collider3DEditorBase + { + SerializedProperty m_Center; + SerializedProperty m_Radius; + SerializedProperty m_Height; + SerializedProperty m_Direction; + + public override void OnEnable() + { + base.OnEnable(); + + m_Center = serializedObject.FindProperty("m_Center"); + m_Radius = serializedObject.FindProperty("m_Radius"); + m_Height = serializedObject.FindProperty("m_Height"); + m_Direction = serializedObject.FindProperty("m_Direction"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.EditorToolbarForTarget(EditorGUIUtility.TrTempContent("Edit Collider"), target); + + EditorGUILayout.PropertyField(m_IsTrigger); + EditorGUILayout.PropertyField(m_Material); + EditorGUILayout.PropertyField(m_Center); + EditorGUILayout.PropertyField(m_Radius); + EditorGUILayout.PropertyField(m_Height); + EditorGUILayout.PropertyField(m_Direction); + + serializedObject.ApplyModifiedProperties(); + } + } } diff --git a/Editor/Mono/Inspector/CharacterJointEditor.cs b/Editor/Mono/Inspector/CharacterJointEditor.cs index 739a17d697..a2ba41b40d 100644 --- a/Editor/Mono/Inspector/CharacterJointEditor.cs +++ b/Editor/Mono/Inspector/CharacterJointEditor.cs @@ -2,13 +2,16 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License -using UnityEditor.IMGUI.Controls; +using UnityEditor.EditorTools; using UnityEngine; namespace UnityEditor { [CustomEditor(typeof(CharacterJoint)), CanEditMultipleObjects] - class CharacterJointEditor : JointEditor + class CharacterJointEditor : JointEditor {} + + [EditorTool("Edit Character Joint", typeof(CharacterJoint))] + class CharacterJointTool : JointTool { protected override void DoAngularLimitHandles(CharacterJoint joint) { diff --git a/Editor/Mono/Inspector/ClothInspector.cs b/Editor/Mono/Inspector/ClothInspector.cs index a34a632dd2..5d46640c90 100644 --- a/Editor/Mono/Inspector/ClothInspector.cs +++ b/Editor/Mono/Inspector/ClothInspector.cs @@ -23,6 +23,8 @@ class ClothInspectorState : ScriptableSingleton [SerializeField] public bool PaintCollisionSphereDistanceEnabled = false; [SerializeField] public float PaintMaxDistance = 0.2f; [SerializeField] public float PaintCollisionSphereDistance = 0.0f; + [SerializeField] public bool SetMaxDistance = false; + [SerializeField] public bool SetCollisionSphereDistance = false; [SerializeField] public ClothInspector.ToolMode ToolMode = ClothInspector.ToolMode.Paint; [SerializeField] public ClothInspector.CollToolMode CollToolMode = ClothInspector.CollToolMode.Select; [SerializeField] public float BrushRadius = 0.075f; @@ -33,6 +35,8 @@ class ClothInspectorState : ScriptableSingleton [SerializeField] public float InterCollisionDistance = 0.1f; [SerializeField] public float InterCollisionStiffness = 0.2f; [SerializeField] public float ConstraintSize = 0.05f; + [SerializeField] public float GradientStartValue = 0.0f; + [SerializeField] public float GradientEndValue = 1.0f; } [CustomEditor(typeof(Cloth))] @@ -40,7 +44,7 @@ class ClothInspectorState : ScriptableSingleton class ClothInspector : Editor { public enum DrawMode { MaxDistance = 1, CollisionSphereDistance }; - public enum ToolMode { Select, Paint }; + public enum ToolMode { Select, Paint, GradientTool }; public enum CollToolMode { Select, Paint, Erase }; enum RectSelectionMode { Replace, Add, Substract }; public enum CollisionVisualizationMode { SelfCollision, InterCollision }; @@ -56,7 +60,6 @@ public enum CollisionVisualizationMode { SelfCollision, InterCollision }; Vector3 m_BrushNorm; int m_BrushFace = -1; - int m_MouseOver = -1; Vector3[] m_LastVertices; Vector2 m_SelectStartPoint; Vector2 m_SelectMousePoint; @@ -67,6 +70,9 @@ public enum CollisionVisualizationMode { SelfCollision, InterCollision }; RectSelectionMode m_RectSelectionMode = RectSelectionMode.Add; int m_NumVerts = 0; + Vector3 m_GradientStartPoint; + Vector3 m_GradientEndPoint; + const float kDisabledValue = float.MaxValue; static Texture2D s_ColorTexture = null; @@ -79,7 +85,8 @@ public enum CollisionVisualizationMode { SelfCollision, InterCollision }; public static ToolMode[] s_ToolMode = { ToolMode.Paint, - ToolMode.Select + ToolMode.Select, + ToolMode.GradientTool }; SerializedProperty m_SelfCollisionDistance; @@ -99,6 +106,10 @@ 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 gradientStartString = EditorGUIUtility.TrTextContent("Gradient Start"); + public static readonly GUIContent gradientEndString = EditorGUIUtility.TrTextContent("Gradient End"); + public static readonly GUIContent setMaxDistanceString = EditorGUIUtility.TrTextContent("Max Distance"); + public static readonly GUIContent setCollisionSphereDistanceString = EditorGUIUtility.TrTextContent("Surface Penetration"); 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"); @@ -116,7 +127,8 @@ private static class Styles public static GUIContent[] toolIcons = { EditorGUIUtility.TrTextContent("Select"), - EditorGUIUtility.TrTextContent("Paint") + EditorGUIUtility.TrTextContent("Paint"), + EditorGUIUtility.TrTextContent("Gradient Tool") }; public static GUIContent[] drawModeStrings = @@ -190,9 +202,7 @@ DrawMode drawMode } Cloth cloth => (Cloth)target; - public bool editingConstraints => EditMode.editMode == EditMode.SceneViewEditMode.ClothConstraints && EditMode.IsOwner(this); - public bool editingSelfAndInterCollisionParticles => EditMode.editMode == EditMode.SceneViewEditMode.ClothSelfAndInterCollisionParticles && EditMode.IsOwner(this); GUIContent GetDrawModeString(DrawMode mode) @@ -249,6 +259,12 @@ public override void OnInspectorGUI() GUILayout.EndHorizontal(); } + if (m_SkinnedMeshRenderer.transform.hasChanged) + { + InitClothParticlesInWorldSpace(); + m_SkinnedMeshRenderer.transform.hasChanged = false; + } + if (editingSelfAndInterCollisionParticles) { if ((state.SetSelfAndInterCollision) || ((state.CollToolMode == CollToolMode.Paint) || (state.CollToolMode == CollToolMode.Erase))) @@ -758,6 +774,130 @@ void SelectionGUI() } } + void GradientToolGUI() + { + if (m_ParticleSelection == null) + { + return; + } + + ClothSkinningCoefficient[] coefficients = cloth.coefficients; + + int numSelection = 0; + int numParticleSelection = m_ParticleSelection.Length; + for (int i = 0; i < numParticleSelection; i++) + { + if (m_ParticleSelection[i]) + { + numSelection++; + } + } + + EditGradientStart(); + EditGradientEnd(); + + if (numSelection == 0) + { + state.SetMaxDistance = false; + state.SetCollisionSphereDistance = false; + } + + Vector3 gradientDirection = m_GradientEndPoint - m_GradientStartPoint; + + using (new EditorGUI.DisabledScope(numSelection == 0)) + { + EditorGUILayout.BeginHorizontal(); + EditorGUI.BeginChangeCheck(); + bool setMaxDistance = EditorGUILayout.Toggle(GUIContent.none, state.SetMaxDistance); + if (EditorGUI.EndChangeCheck()) + { + state.SetMaxDistance = setMaxDistance; + int numCoefficients = coefficients.Length; + for (int i = 0; i < numCoefficients; i++) + { + if (m_ParticleSelection[i]) + { + Vector3 pointOnLine = HandleUtility.ProjectPointLine(m_ClothParticlesInWorldSpace[i], m_GradientStartPoint, m_GradientEndPoint); + Vector3 gradientStartToPoint = pointOnLine - m_GradientStartPoint; + float lerpParameter = gradientStartToPoint.magnitude / gradientDirection.magnitude; + float maxDistanceNew = Mathf.Lerp(state.GradientStartValue, state.GradientEndValue, lerpParameter); + coefficients[i].maxDistance = maxDistanceNew; + } + } + cloth.coefficients = coefficients; + Undo.RegisterCompleteObjectUndo(target, "Change Cloth Coefficients"); + } + + EditorGUILayout.LabelField(Styles.setMaxDistanceString); + EditorGUILayout.EndHorizontal(); + } + + using (new EditorGUI.DisabledScope(numSelection == 0)) + { + EditorGUILayout.BeginHorizontal(); + EditorGUI.BeginChangeCheck(); + bool setCollisionSphereDistance = EditorGUILayout.Toggle(GUIContent.none, state.SetCollisionSphereDistance); + if (EditorGUI.EndChangeCheck()) + { + state.SetCollisionSphereDistance = setCollisionSphereDistance; + int numCoefficients = coefficients.Length; + for (int i = 0; i < numCoefficients; i++) + { + if (m_ParticleSelection[i]) + { + Vector3 pointOnLine = HandleUtility.ProjectPointLine(m_ClothParticlesInWorldSpace[i], m_GradientStartPoint, m_GradientEndPoint); + Vector3 gradientStartToPoint = pointOnLine - m_GradientStartPoint; + float lerpParameter = gradientStartToPoint.magnitude / gradientDirection.magnitude; + float collisionSphereDistanceNew = Mathf.Lerp(state.GradientStartValue, state.GradientEndValue, lerpParameter); + coefficients[i].collisionSphereDistance = collisionSphereDistanceNew; + } + } + cloth.coefficients = coefficients; + Undo.RegisterCompleteObjectUndo(target, "Change Cloth Coefficients"); + } + + EditorGUILayout.LabelField(Styles.setCollisionSphereDistanceString); + EditorGUILayout.EndHorizontal(); + } + + using (new EditorGUI.DisabledScope(true)) + { + GUILayout.BeginHorizontal(); + if (numSelection > 0) + { + GUILayout.FlexibleSpace(); + GUILayout.Label(numSelection + " selected"); + } + else + { + GUILayout.Label("Select cloth vertices to edit their constraints."); + GUILayout.FlexibleSpace(); + } + GUILayout.EndHorizontal(); + } + + if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Backspace) + { + int numCoefficients = coefficients.Length; + for (int i = 0; i < numCoefficients; i++) + { + if (m_ParticleSelection[i]) + { + switch (drawMode) + { + case DrawMode.MaxDistance: + coefficients[i].maxDistance = kDisabledValue; + break; + case DrawMode.CollisionSphereDistance: + coefficients[i].collisionSphereDistance = kDisabledValue; + break; + } + } + } + cloth.coefficients = coefficients; + } + } + void CollSelectionGUI() { if (!IsMeshValid()) @@ -835,6 +975,32 @@ void EditBrushSize() } } + void EditGradientStart() + { + EditorGUI.BeginChangeCheck(); + float fieldValue = EditorGUILayout.FloatField(Styles.gradientStartString, state.GradientStartValue); + bool changed = EditorGUI.EndChangeCheck(); + if (changed) + { + state.GradientStartValue = fieldValue; + if (state.GradientStartValue < 0.0f) + state.GradientStartValue = 0.0f; + } + } + + void EditGradientEnd() + { + EditorGUI.BeginChangeCheck(); + float fieldValue = EditorGUILayout.FloatField(Styles.gradientEndString, state.GradientEndValue); + bool changed = EditorGUI.EndChangeCheck(); + if (changed) + { + state.GradientEndValue = fieldValue; + if (state.GradientEndValue < 0.0f) + state.GradientEndValue = 0.0f; + } + } + void PaintGUI() { state.PaintMaxDistance = PaintField(state.PaintMaxDistance, ref state.PaintMaxDistanceEnabled, DrawMode.MaxDistance); @@ -972,6 +1138,9 @@ bool UpdateRectParticleSelection() Ray botLeft = HandleUtility.GUIPointToWorldRay(new Vector2(minX, maxY)); Ray botRight = HandleUtility.GUIPointToWorldRay(new Vector2(maxX, maxY)); + m_GradientStartPoint = (topLeft.origin + botLeft.origin) * 0.5f; + m_GradientEndPoint = (topRight.origin + botRight.origin) * 0.5f; + Plane top = new Plane(topRight.origin + topRight.direction, topLeft.origin + topLeft.direction, topLeft.origin); Plane bottom = new Plane(botLeft.origin + botLeft.direction, botRight.origin + botRight.direction, botRight.origin); Plane left = new Plane(topLeft.origin + topLeft.direction, botLeft.origin + botLeft.direction, botLeft.origin); @@ -1256,6 +1425,99 @@ void PaintPreSceneGUI(int id) } } + void GradientToolPreScenGUI(int id) + { + Event e = Event.current; + switch (e.GetTypeForControl(id)) + { + case EventType.MouseDown: + if (e.alt || e.control || e.command || e.button != 0) + break; + GUIUtility.hotControl = id; + int found = GetMouseVertex(e); + if (found != -1) + { + if (e.shift) + m_ParticleSelection[found] = !m_ParticleSelection[found]; + else + { + int length = m_ParticleSelection.Length; + for (int i = 0; i < length; i++) + m_ParticleSelection[i] = false; + m_ParticleSelection[found] = true; + } + m_DidSelect = true; + Repaint(); + } + else + m_DidSelect = false; + + m_SelectStartPoint = e.mousePosition; + e.Use(); + break; + + case EventType.MouseDrag: + if (GUIUtility.hotControl == id) + { + if (!m_RectSelecting && (e.mousePosition - m_SelectStartPoint).magnitude > 2f) + { + if (!(e.alt || e.control || e.command)) + { + EditorApplication.modifierKeysChanged += SendCommandsOnModifierKeys; + m_RectSelecting = true; + RectSelectionModeFromEvent(); + } + } + if (m_RectSelecting) + { + m_SelectMousePoint = new Vector2(Mathf.Max(e.mousePosition.x, 0), Mathf.Max(e.mousePosition.y, 0)); + RectSelectionModeFromEvent(); + UpdateRectParticleSelection(); + e.Use(); + } + } + break; + + case EventType.ExecuteCommand: + if (m_RectSelecting && e.commandName == EventCommandNames.ModifierKeysChanged) + { + RectSelectionModeFromEvent(); + UpdateRectParticleSelection(); + } + break; + + case EventType.MouseUp: + if (GUIUtility.hotControl == id && e.button == 0) + { + GUIUtility.hotControl = 0; + + if (m_RectSelecting) + { + EditorApplication.modifierKeysChanged -= SendCommandsOnModifierKeys; + m_RectSelecting = false; + RectSelectionModeFromEvent(); + ApplyRectSelection(); + } + else if (!m_DidSelect) + { + if (!(e.alt || e.control || e.command)) + { + // If nothing was clicked, deselect all + ClothSkinningCoefficient[] coefficients = cloth.coefficients; + int length = coefficients.Length; + for (int i = 0; i < length; i++) + m_ParticleSelection[i] = false; + } + } + // Disable text focus when selection changes, otherwise we cannot update inspector fields + // if text is currently selected. + GUIUtility.keyboardControl = 0; + SceneView.RepaintAll(); + } + break; + } + } + private void OnPreSceneGUICallback(SceneView sceneView) { // Multi-editing in scene not supported @@ -1301,10 +1563,8 @@ void OnPreSceneGUI() case EventType.MouseMove: case EventType.MouseDrag: - int oldMouseOver = m_MouseOver; - m_MouseOver = GetMouseVertex(e); - if (m_MouseOver != oldMouseOver) - SceneView.RepaintAll(); + GetMouseVertex(e); + SceneView.RepaintAll(); break; } @@ -1319,6 +1579,9 @@ void OnPreSceneGUI() case ToolMode.Paint: PaintPreSceneGUI(id); break; + case ToolMode.GradientTool: + GradientToolPreScenGUI(id); + break; } } @@ -1387,7 +1650,7 @@ void OnSceneEditConstraintsGUI() } Handles.BeginGUI(); - if (m_RectSelecting && state.ToolMode == ToolMode.Select && Event.current.type == EventType.Repaint) + if (m_RectSelecting && (state.ToolMode == ToolMode.Select || state.ToolMode == ToolMode.GradientTool) && Event.current.type == EventType.Repaint) EditorStyles.selectionRect.Draw(EditorGUIExt.FromToRect(m_SelectStartPoint, m_SelectMousePoint), GUIContent.none, false, false, false, false); Handles.EndGUI(); @@ -1544,6 +1807,10 @@ void ConstraintEditing(UnityObject unused, SceneView sceneView) Tools.current = Tool.None; PaintGUI(); break; + case ToolMode.GradientTool: + Tools.current = Tool.None; + GradientToolGUI(); + break; } if (m_SkinnedMeshRenderer.sharedMesh == null) diff --git a/Editor/Mono/Inspector/ConfigurableJointEditor.cs b/Editor/Mono/Inspector/ConfigurableJointEditor.cs index 785e7141da..9a46217cf6 100644 --- a/Editor/Mono/Inspector/ConfigurableJointEditor.cs +++ b/Editor/Mono/Inspector/ConfigurableJointEditor.cs @@ -2,12 +2,16 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License +using UnityEditor.EditorTools; using UnityEngine; namespace UnityEditor { [CustomEditor(typeof(ConfigurableJoint)), CanEditMultipleObjects] - class ConfigurableJointEditor : JointEditor + class ConfigurableJointEditor : JointEditor {} + + [EditorTool("Edit Configurable Joint", typeof(ConfigurableJoint))] + class ConfigurableJointTool : JointTool { protected override void GetActors( ConfigurableJoint joint, diff --git a/Editor/Mono/Inspector/Editor.cs b/Editor/Mono/Inspector/Editor.cs index 0e25e66fcc..e2fd908707 100644 --- a/Editor/Mono/Inspector/Editor.cs +++ b/Editor/Mono/Inspector/Editor.cs @@ -902,14 +902,15 @@ internal static Rect DrawHeaderGUI(Editor editor, string header, float leftMargi // Help and Settings Rect titleRect; + var titleHeight = EditorGUI.lineHeight; if (editor) { Rect helpAndSettingsRect = editor.DrawHeaderHelpAndSettingsGUI(r); float rectX = r.x + kImageSectionWidth; - titleRect = new Rect(rectX, r.y + 6, (helpAndSettingsRect.x - rectX) - 4, 16); + titleRect = new Rect(rectX, r.y + 6, (helpAndSettingsRect.x - rectX) - 4, titleHeight); } else - titleRect = new Rect(r.x + kImageSectionWidth, r.y + 6, r.width - kImageSectionWidth, 16); + titleRect = new Rect(r.x + kImageSectionWidth, r.y + 6, r.width - kImageSectionWidth, titleHeight); // Title if (editor) @@ -954,7 +955,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; diff --git a/Editor/Mono/Inspector/EditorElement.cs b/Editor/Mono/Inspector/EditorElement.cs index 275e9b3ee4..57c47913ea 100644 --- a/Editor/Mono/Inspector/EditorElement.cs +++ b/Editor/Mono/Inspector/EditorElement.cs @@ -104,8 +104,6 @@ void Init() if (EditorNeedsVerticalOffset(editorTarget)) { - // This is madness - m_InspectorElement.cacheAsBitmap = false; m_InspectorElement.style.overflow = Overflow.Hidden; } diff --git a/Editor/Mono/Inspector/EditorSettingsInspector.cs b/Editor/Mono/Inspector/EditorSettingsInspector.cs index 15e4bf078e..ba6633eb26 100644 --- a/Editor/Mono/Inspector/EditorSettingsInspector.cs +++ b/Editor/Mono/Inspector/EditorSettingsInspector.cs @@ -36,6 +36,7 @@ class Content 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 overlayIcons = EditorGUIUtility.TrTextContent("Overlay Icons", "Should version control status icons be shown in project view."); public static GUIContent assetPipeline = EditorGUIUtility.TrTextContent("Asset Pipeline (experimental)"); public static GUIContent cacheServer = EditorGUIUtility.TrTextContent("Cache Server"); @@ -44,6 +45,7 @@ class Content public static GUIContent graphics = EditorGUIUtility.TrTextContent("Graphics"); public static GUIContent showLightmapResolutionOverlay = EditorGUIUtility.TrTextContent("Show Lightmap Resolution Overlay"); + public static GUIContent useLegacyProbeSampleCount = EditorGUIUtility.TrTextContent("Use legacy Light Probe sample counts", "Uses fixed Light Probe sample counts for baking with the Progressive Lightmapper. The sample counts are: 64 direct samples, 2048 indirect samples and 2048 environment samples."); public static GUIContent spritePacker = EditorGUIUtility.TrTextContent("Sprite Packer"); @@ -471,6 +473,13 @@ public override void OnInspectorGUI() EditorUserSettings.overwriteFailedCheckoutAssets = EditorGUILayout.Toggle(Content.overwriteFailedCheckoutAssets, EditorUserSettings.overwriteFailedCheckoutAssets); } + var newOverlayIcons = EditorGUILayout.Toggle(Content.overlayIcons, EditorUserSettings.overlayIcons); + if (newOverlayIcons != EditorUserSettings.overlayIcons) + { + EditorUserSettings.overlayIcons = newOverlayIcons; + EditorApplication.RequestRepaintAllViews(); + } + GUI.enabled = editorEnabled; // Semantic merge popup @@ -549,6 +558,15 @@ public override void OnInspectorGUI() if (EditorGUI.EndChangeCheck()) LightmapVisualization.showResolution = showRes; + EditorGUI.BeginChangeCheck(); + bool useLegacyProbeSampleCountValue = EditorSettings.useLegacyProbeSampleCount; + useLegacyProbeSampleCountValue = EditorGUILayout.Toggle(Content.useLegacyProbeSampleCount, useLegacyProbeSampleCountValue); + if (EditorGUI.EndChangeCheck()) + { + EditorApplication.RequestRepaintAllViews(); + EditorSettings.useLegacyProbeSampleCount = useLegacyProbeSampleCountValue; + } + GUILayout.Space(10); GUI.enabled = true; 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/HingeJointEditor.cs b/Editor/Mono/Inspector/HingeJointEditor.cs index fd893ff894..713bb9558d 100644 --- a/Editor/Mono/Inspector/HingeJointEditor.cs +++ b/Editor/Mono/Inspector/HingeJointEditor.cs @@ -2,30 +2,20 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License -using UnityEditor.IMGUI.Controls; using UnityEngine; +using UnityEditor.EditorTools; namespace UnityEditor { [CustomEditor(typeof(HingeJoint)), CanEditMultipleObjects] class HingeJointEditor : JointEditor { - private static readonly GUIContent s_WarningMessage = - EditorGUIUtility.TrTextContent("Min and max limits must be within the range [-180, 180]."); - - private SerializedProperty m_MinLimit; - private SerializedProperty m_MaxLimit; + static readonly GUIContent s_WarningMessage = EditorGUIUtility.TrTextContent("Min and max limits must be within the range [-180, 180]."); + SerializedProperty m_MinLimit; + SerializedProperty m_MaxLimit; void OnEnable() { - angularLimitHandle.yMotion = ConfigurableJointMotion.Locked; - angularLimitHandle.zMotion = ConfigurableJointMotion.Locked; - - angularLimitHandle.yHandleColor = Color.clear; - angularLimitHandle.zHandleColor = Color.clear; - - angularLimitHandle.xRange = new Vector2(-Physics.k_MaxFloatMinusEpsilon, Physics.k_MaxFloatMinusEpsilon); - m_MinLimit = serializedObject.FindProperty("m_Limits.min"); m_MaxLimit = serializedObject.FindProperty("m_Limits.max"); } @@ -40,6 +30,21 @@ public override void OnInspectorGUI() if (min < -180f || min > 180f || max < -180f || max > 180f) EditorGUILayout.HelpBox(s_WarningMessage.text, MessageType.Warning); } + } + + [EditorTool("Edit Hinge Joint", typeof(HingeJoint))] + class HingeJointTool : JointTool + { + void OnEnable() + { + angularLimitHandle.yMotion = ConfigurableJointMotion.Locked; + angularLimitHandle.zMotion = ConfigurableJointMotion.Locked; + + angularLimitHandle.yHandleColor = Color.clear; + angularLimitHandle.zHandleColor = Color.clear; + + angularLimitHandle.xRange = new Vector2(-Physics.k_MaxFloatMinusEpsilon, Physics.k_MaxFloatMinusEpsilon); + } protected override void GetActors( HingeJoint joint, diff --git a/Editor/Mono/Inspector/InspectorWindow.cs b/Editor/Mono/Inspector/InspectorWindow.cs index f3387f07a9..027e17b0c0 100644 --- a/Editor/Mono/Inspector/InspectorWindow.cs +++ b/Editor/Mono/Inspector/InspectorWindow.cs @@ -763,15 +763,17 @@ internal virtual void RebuildContentsContainers() Profiler.EndSample(); } - private Rect DropRectangle + private Rect bottomAreaDropRectangle { get { + var worldEditorRect = editorsElement.LocalToWorld(editorsElement.rect); + var worldRootRect = rootVisualElement.LocalToWorld(rootVisualElement.rect); return new Rect( - editorsElement.rect.x, - editorsElement.rect.y + editorsElement.rect.height, - editorsElement.rect.width, - rootVisualElement.rect.height - editorsElement.rect.height); + worldEditorRect.x, + worldEditorRect.y + worldEditorRect.height, + worldEditorRect.width, + worldRootRect.y + worldRootRect.height - worldEditorRect.height - worldEditorRect.y); } } @@ -779,7 +781,7 @@ void DragOverBottomArea(DragUpdatedEvent dragUpdatedEvent) { if (DragAndDrop.objectReferences.Any()) { - if (editorsElement.ContainsPoint(dragUpdatedEvent.mousePosition)) + if (editorsElement.ContainsPoint(editorsElement.WorldToLocal(dragUpdatedEvent.mousePosition))) { return; } @@ -790,13 +792,13 @@ void DragOverBottomArea(DragUpdatedEvent dragUpdatedEvent) return; } - editorDragging.HandleDraggingInBottomArea(tracker.activeEditors, DropRectangle, lastChild.layout); + editorDragging.HandleDraggingInBottomArea(tracker.activeEditors, bottomAreaDropRectangle, lastChild.layout); } } void DragPerformInBottomArea(DragPerformEvent dragPerformedEvent) { - if (editorsElement.ContainsPoint(dragPerformedEvent.mousePosition)) + if (editorsElement.ContainsPoint(editorsElement.WorldToLocal(dragPerformedEvent.mousePosition))) { return; } @@ -807,7 +809,7 @@ void DragPerformInBottomArea(DragPerformEvent dragPerformedEvent) return; } - editorDragging.HandleDragPerformInBottomArea(tracker.activeEditors, DropRectangle, lastChild.layout); + editorDragging.HandleDragPerformInBottomArea(tracker.activeEditors, bottomAreaDropRectangle, lastChild.layout); } protected bool m_FirstInitialize; @@ -1221,10 +1223,8 @@ internal static void VersionControlBar(Editor assetEditor) Asset asset = Provider.GetAssetByPath(assetPath); if (asset == null) return; - var vcsAssetPath = asset.path; - var underAssets = vcsAssetPath.StartsWith("Assets"); - var underProjectSettings = vcsAssetPath.StartsWith("ProjectSettings"); - if (!(underAssets || underProjectSettings)) + + if (!Provider.PathIsVersioned(asset.path)) return; var connected = Provider.isActive; @@ -1235,7 +1235,7 @@ internal static void VersionControlBar(Editor assetEditor) // if it exists -- so for files under project settings, it ends up returning // a valid entry for the non-existing meta file. So just don't do it. Asset metaAsset = null; - if (!underProjectSettings) + if (Provider.PathHasMetaFile(asset.path)) metaAsset = Provider.GetAssetByPath(assetPath.Trim('/') + ".meta"); string currentState = asset.StateToString(); diff --git a/Editor/Mono/Inspector/JointEditor.cs b/Editor/Mono/Inspector/JointEditor.cs index 48236c4cf3..9466513f3c 100644 --- a/Editor/Mono/Inspector/JointEditor.cs +++ b/Editor/Mono/Inspector/JointEditor.cs @@ -3,6 +3,7 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; +using UnityEditor.EditorTools; using UnityEditor.IMGUI.Controls; using UnityEditorInternal; using UnityEngine; @@ -10,7 +11,7 @@ namespace UnityEditor { - internal class JointCommonEditor : Editor + class JointCommonEditor : Editor { public static void CheckConnectedBody(Editor editor) { @@ -35,42 +36,18 @@ public override void OnInspectorGUI() [CustomEditor(typeof(FixedJoint))] [CanEditMultipleObjects] - internal class FixedJointEditor : JointCommonEditor + class FixedJointEditor : JointCommonEditor { } [CustomEditor(typeof(SpringJoint))] [CanEditMultipleObjects] - internal class SpringJointEditor : JointCommonEditor + class SpringJointEditor : JointCommonEditor { } abstract class JointEditor : Editor where T : Joint { - protected static class Styles - { - public static readonly GUIContent editAngularLimitsButton = new GUIContent(EditorGUIUtility.IconContent("JointAngularLimits")); - public static readonly string editAngularLimitsUndoMessage = EditorGUIUtility.TrTextContent("Change Joint Angular Limits").text; - - static Styles() - { - editAngularLimitsButton.tooltip = EditorGUIUtility.TrTextContent("Edit joint angular limits.").text; - } - } - - protected static float GetAngularLimitHandleSize(Vector3 position) - { - return HandleUtility.GetHandleSize(position); - } - - protected JointAngularLimitHandle angularLimitHandle { get { return m_AngularLimitHandle; } } - private JointAngularLimitHandle m_AngularLimitHandle = new JointAngularLimitHandle(); - - protected bool editingAngularLimits - { - get { return EditMode.editMode == EditMode.SceneViewEditMode.JointAngularLimits && EditMode.IsOwner(this); } - } - public override void OnInspectorGUI() { JointCommonEditor.CheckConnectedBody(this); @@ -82,30 +59,53 @@ protected void DoInspectorEditButtons() { T joint = (T)target; EditorGUI.BeginDisabledGroup(joint.gameObject.activeSelf == false); - EditMode.DoEditModeInspectorModeButton( - EditMode.SceneViewEditMode.JointAngularLimits, - "Edit Joint Angular Limits", - Styles.editAngularLimitsButton, - this - ); + EditorGUILayout.EditorToolbarForTarget(EditorGUIUtility.TrTempContent("Edit Angular Limits"), target); EditorGUI.EndDisabledGroup(); } internal override Bounds GetWorldBoundsOfTarget(UnityObject targetObject) { var bounds = base.GetWorldBoundsOfTarget(targetObject); + // ensure joint's anchor point is included in bounds - bounds.Encapsulate(GetAngularLimitHandleMatrix((T)targetObject).MultiplyPoint3x4(Vector3.zero)); + var jointTool = EditorToolContext.activeTool as JointTool; + + if (jointTool != null) + bounds.Encapsulate(jointTool.GetAngularLimitHandleMatrix((T)targetObject).MultiplyPoint3x4(Vector3.zero)); + return bounds; } + } + + abstract class JointTool : EditorTool where T : Joint + { + protected static class Styles + { + public static readonly string editAngularLimitsUndoMessage = L10n.Tr("Change Joint Angular Limits"); + } - protected virtual void OnSceneGUI() + public override GUIContent toolbarIcon { - if (!target) - return; - if (editingAngularLimits) + get { return EditorGUIUtility.IconContent("JointAngularLimits"); } + } + + protected static float GetAngularLimitHandleSize(Vector3 position) + { + return HandleUtility.GetHandleSize(position); + } + + protected JointAngularLimitHandle angularLimitHandle { get { return m_AngularLimitHandle; } } + JointAngularLimitHandle m_AngularLimitHandle = new JointAngularLimitHandle(); + + public override void OnToolGUI(EditorWindow window) + { + foreach (var obj in targets) { - T joint = (T)target; + T joint = obj as T; + + if (joint == null) + continue; + EditorGUI.BeginChangeCheck(); using (new Handles.DrawingScope(GetAngularLimitHandleMatrix(joint))) @@ -145,7 +145,7 @@ out bool rightHandedLimit } } - private Matrix4x4 GetAngularLimitHandleMatrix(T joint) + internal Matrix4x4 GetAngularLimitHandleMatrix(T joint) { Rigidbody dynamicActor, connectedActor; int jointFrameActorIndex; diff --git a/Editor/Mono/Inspector/LightEditor.cs b/Editor/Mono/Inspector/LightEditor.cs index 24e53542dc..8ce72e2081 100644 --- a/Editor/Mono/Inspector/LightEditor.cs +++ b/Editor/Mono/Inspector/LightEditor.cs @@ -20,6 +20,7 @@ public sealed class Settings private SerializedObject m_SerializedObject; public SerializedProperty lightType { get; private set; } + public SerializedProperty lightShape { get; private set; } public SerializedProperty range { get; private set; } public SerializedProperty spotAngle { get; private set; } public SerializedProperty innerSpotAngle { get; private set; } @@ -169,6 +170,7 @@ internal bool showCookieWarning public void OnEnable() { lightType = m_SerializedObject.FindProperty("m_Type"); + lightShape = m_SerializedObject.FindProperty("m_Shape"); range = m_SerializedObject.FindProperty("m_Range"); spotAngle = m_SerializedObject.FindProperty("m_SpotAngle"); innerSpotAngle = m_SerializedObject.FindProperty("m_InnerSpotAngle"); @@ -680,7 +682,7 @@ private void CommandBufferGUI() { light.RemoveCommandBuffer(le, cb); SceneView.RepaintAll(); - GameView.RepaintAll(); + PreviewEditorWindow.RepaintAll(); GUIUtility.ExitGUI(); } } @@ -694,7 +696,7 @@ private void CommandBufferGUI() { light.RemoveAllCommandBuffers(); SceneView.RepaintAll(); - GameView.RepaintAll(); + PreviewEditorWindow.RepaintAll(); } } EditorGUI.indentLevel--; diff --git a/Editor/Mono/Inspector/LightProbeGroupInspector.cs b/Editor/Mono/Inspector/LightProbeGroupInspector.cs index 3058e94750..ccca7002b2 100644 --- a/Editor/Mono/Inspector/LightProbeGroupInspector.cs +++ b/Editor/Mono/Inspector/LightProbeGroupInspector.cs @@ -25,7 +25,6 @@ internal class LightProbeGroupEditor : IEditablePoint private readonly LightProbeGroup m_Group; private bool m_ShouldRecalculateTetrahedra; private bool m_SourcePositionsDirty; - private bool m_SelectedProbesDirty; private Vector3 m_LastPosition = Vector3.zero; private Quaternion m_LastRotation = Quaternion.identity; private Vector3 m_LastScale = Vector3.one; @@ -38,7 +37,6 @@ public LightProbeGroupEditor(LightProbeGroup group) m_Group = group; m_ShouldRecalculateTetrahedra = false; m_SourcePositionsDirty = false; - m_SelectedProbesDirty = false; m_SerializedSelectedProbes = ScriptableObject.CreateInstance(); m_SerializedSelectedProbes.hideFlags = HideFlags.HideAndDontSave; } @@ -61,8 +59,6 @@ private void SelectProbe(int i) { if (!m_Selection.Contains(i)) m_Selection.Add(i); - - MarkSelectedProbesDirty(); } public void SelectAllProbes() @@ -72,16 +68,12 @@ public void SelectAllProbes() var count = m_SourcePositions.Count; for (var i = 0; i < count; i++) m_Selection.Add(i); - - MarkSelectedProbesDirty(); } public void DeselectProbes() { m_Selection.Clear(); m_SerializedSelectedProbes.m_Selection = m_Selection; - - MarkSelectedProbesDirty(); } private IEnumerable SelectedProbePositions() @@ -102,7 +94,6 @@ public void DuplicateSelectedProbes() } MarkSourcePositionsDirty(); - MarkSelectedProbesDirty(); } private void CopySelectedProbes() @@ -187,7 +178,6 @@ public void RemoveSelectedProbes() } DeselectProbes(); MarkSourcePositionsDirty(); - MarkSelectedProbesDirty(); } public void PullProbePositions() @@ -207,11 +197,7 @@ public void PushProbePositions() m_SourcePositionsDirty = false; } - if (m_SelectedProbesDirty) - { - m_SerializedSelectedProbes.m_Selection = m_Selection; - m_SelectedProbesDirty = false; - } + m_SerializedSelectedProbes.m_Selection = m_Selection; } private void DrawTetrahedra() @@ -380,11 +366,6 @@ public void MarkSourcePositionsDirty() m_SourcePositionsDirty = true; } - public void MarkSelectedProbesDirty() - { - m_SelectedProbesDirty = true; - } - public Bounds selectedProbeBounds { get diff --git a/Editor/Mono/Inspector/MeshRendererEditor.cs b/Editor/Mono/Inspector/MeshRendererEditor.cs index 092e0a766f..3a83e07d98 100644 --- a/Editor/Mono/Inspector/MeshRendererEditor.cs +++ b/Editor/Mono/Inspector/MeshRendererEditor.cs @@ -79,7 +79,7 @@ public override void OnInspectorGUI() } LightingSettingsGUI(true); - OtherSettingsGUI(true); + OtherSettingsGUI(true, false, false, true); serializedObject.ApplyModifiedProperties(); } 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/PlayerSettingsEditor/PlayerSettingsEditor.cs b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs index 798244deca..38e6f56a15 100644 --- a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs +++ b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs @@ -12,9 +12,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; using UnityEditor.Modules; -using UnityEditor.Scripting.ScriptCompilation; using UnityEngine.Events; using GraphicsDeviceType = UnityEngine.Rendering.GraphicsDeviceType; using VR = UnityEditorInternal.VR; @@ -190,6 +188,7 @@ class SettingsContent 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"); 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 legacyClampBlendShapeWeights = EditorGUIUtility.TrTextContent("Clamp BlendShapes (Deprecated)*", "If set, the range of BlendShape weights in SkinnedMeshRenderers will be clamped."); + public static string undoChangedBundleIdentifierString { get { return LocalizationDatabase.GetLocalizedString("Changed macOS bundleIdentifier"); } } public static string undoChangedBuildNumberString { get { return LocalizationDatabase.GetLocalizedString("Changed macOS build number"); } } public static string undoChangedBatchingString { get { return LocalizationDatabase.GetLocalizedString("Changed Batching Settings"); } } @@ -304,7 +303,6 @@ PlayerSettingsSplashScreenEditor splashScreenEditor SerializedProperty m_MetalForceHardShadows; SerializedProperty m_FramebufferDepthMemorylessMode; - SerializedProperty m_DisplayResolutionDialog; SerializedProperty m_DefaultIsNativeResolution; SerializedProperty m_MacRetinaSupport; @@ -336,6 +334,8 @@ PlayerSettingsSplashScreenEditor splashScreenEditor SerializedProperty m_LightmapStreamingEnabled; SerializedProperty m_LightmapStreamingPriority; + SerializedProperty m_HDRBitDepth; + // Legacy SerializedProperty m_LegacyClampBlendShapeWeights; @@ -461,7 +461,6 @@ void OnEnable() m_DefaultIsNativeResolution = FindPropertyAssert("defaultIsNativeResolution"); m_MacRetinaSupport = FindPropertyAssert("macRetinaSupport"); m_CaptureSingleScreen = FindPropertyAssert("captureSingleScreen"); - m_DisplayResolutionDialog = FindPropertyAssert("displayResolutionDialog"); m_SupportedAspectRatios = FindPropertyAssert("m_SupportedAspectRatios"); m_UsePlayerLog = FindPropertyAssert("usePlayerLog"); @@ -567,8 +566,8 @@ public override void OnInspectorGUI() } GUILayout.Label(string.Format(L10n.Tr("Settings for {0}"), validPlatforms[selectedPlatform].title.text)); - // Compensate so settings inside boxes line up with settings at the top, though keep a minimum of 150. - EditorGUIUtility.labelWidth = Mathf.Max(150, EditorGUIUtility.labelWidth - 8); + // Increase the offset to accomodate large labels, though keep a minimum of 150. + EditorGUIUtility.labelWidth = Mathf.Max(150, EditorGUIUtility.labelWidth + 4); BuildPlatform platform = validPlatforms[selectedPlatform]; BuildTargetGroup targetGroup = platform.targetGroup; @@ -934,12 +933,6 @@ public void ResolutionSectionGUI(BuildTargetGroup targetGroup, ISettingEditorExt { GUILayout.Label(SettingsContent.standalonePlayerOptionsTitle, EditorStyles.boldLabel); EditorGUILayout.PropertyField(m_CaptureSingleScreen); - EditorGUILayout.PropertyField(m_DisplayResolutionDialog); - - if (m_DisplayResolutionDialog.intValue > 0) - { - EditorGUILayout.HelpBox(SettingsContent.displayResolutionDialogDeprecationWarning.text, MessageType.Warning, true); - } EditorGUILayout.PropertyField(m_UsePlayerLog); EditorGUILayout.PropertyField(m_ResizableWindow); @@ -1116,6 +1109,11 @@ private void DrawGraphicsDeviceElement(BuildTarget target, Rect rect, int index, else if (name == "OpenGLES2") name = "WebGL 1.0"; } + else if (target == BuildTarget.iOS || target == BuildTarget.tvOS) + { + if (name.Contains("OpenGLES")) + name += " (Deprecated)"; + } GUI.Label(rect, name, EditorStyles.label); } @@ -1148,14 +1146,6 @@ void OpenGLES31OptionsGUI(BuildTargetGroup targetGroup, BuildTarget targetPlatfo void GraphicsAPIsGUIOnePlatform(BuildTargetGroup targetGroup, BuildTarget targetPlatform, string platformTitle) { - // Facebook on windows must be always DX11 - // TODO: Remove this when Facebook platform support contract is over - if (targetGroup == BuildTargetGroup.Facebook && - (targetPlatform == BuildTarget.StandaloneWindows || targetPlatform == BuildTarget.StandaloneWindows64)) - { - return; - } - GraphicsDeviceType[] availableDevices = PlayerSettings.GetSupportedGraphicsAPIs(targetPlatform); // if no devices (e.g. no platform module), or we only have one possible choice, then no // point in having any UI @@ -1616,18 +1606,27 @@ private void OtherSectionRenderingGUI(BuildPlatform platform, BuildTargetGroup t } - bool hdrSupported = false; + bool hdrDisplaySupported = false; bool gfxJobModesSupported = false; bool customLightmapEncodingSupported = (targetGroup == BuildTargetGroup.Standalone); if (settingsExtension != null) { - hdrSupported = settingsExtension.SupportsHighDynamicRangeDisplays(); + hdrDisplaySupported = settingsExtension.SupportsHighDynamicRangeDisplays(); gfxJobModesSupported = settingsExtension.SupportsGfxJobModes(); customLightmapEncodingSupported = customLightmapEncodingSupported || settingsExtension.SupportsCustomLightmapEncoding(); } + else + { + if (targetGroup == BuildTargetGroup.Standalone) + { + GraphicsDeviceType[] gfxAPIs = PlayerSettings.GetGraphicsAPIs(platform.defaultTarget); + + hdrDisplaySupported = gfxAPIs[0] == GraphicsDeviceType.Direct3D11 || gfxAPIs[0] == GraphicsDeviceType.Direct3D12; + } + } // GPU Skinning toggle (only show on relevant platforms) - if (targetGroup != BuildTargetGroup.Facebook && !BuildTargetDiscovery.PlatformHasFlag(platform.defaultTarget, TargetAttributes.GPUSkinningNotSupported)) + if (!BuildTargetDiscovery.PlatformHasFlag(platform.defaultTarget, TargetAttributes.GPUSkinningNotSupported)) { GraphicsDeviceType[] gfxAPIs = PlayerSettings.GetGraphicsAPIs(platform.defaultTarget); bool computeSkinningOnly = @@ -1759,9 +1758,33 @@ private void OtherSectionRenderingGUI(BuildPlatform platform, BuildTargetGroup t PlayerSettings.enableFrameTimingStats = EditorGUILayout.Toggle(SettingsContent.enableFrameTimingStats, PlayerSettings.enableFrameTimingStats); } - if (hdrSupported) + if (hdrDisplaySupported) { - PlayerSettings.useHDRDisplay = EditorGUILayout.Toggle(EditorGUIUtility.TrTextContent("Use display in HDR mode", "Automatically switch the display to HDR output (on supported displays) at start of application."), PlayerSettings.useHDRDisplay); + string label = "Use display in HDR mode"; + string tooltip = "Automatically switch the display to HDR output (on supported displays)" + ((targetGroup == BuildTargetGroup.XboxOne) ? " at start of application." : "."); + PlayerSettings.useHDRDisplay = EditorGUILayout.Toggle(EditorGUIUtility.TrTextContent(label, tooltip), PlayerSettings.useHDRDisplay); + + + if (targetGroup == BuildTargetGroup.Standalone || targetGroup == BuildTargetGroup.WSA) + { + using (new EditorGUI.DisabledScope(!PlayerSettings.useHDRDisplay)) + { + using (new EditorGUI.IndentLevelScope()) + { + EditorGUI.BeginChangeCheck(); + D3DHDRDisplayBitDepth bitDepth = PlayerSettings.D3DHDRBitDepth; + D3DHDRDisplayBitDepth[] bitDepthValues = { D3DHDRDisplayBitDepth.D3DHDRDisplayBitDepth10, D3DHDRDisplayBitDepth.D3DHDRDisplayBitDepth16 }; + GUIContent HDRBitDepthLabel = EditorGUIUtility.TrTextContent("Swap Chain Bit Depth", "Affects the bit depth of the final swap chain format and color space."); + GUIContent[] HDRBitDepthNames = { EditorGUIUtility.TrTextContent("Bit Depth 10"), EditorGUIUtility.TrTextContent("Bit Depth 16")}; + + bitDepth = BuildEnumPopup(HDRBitDepthLabel, bitDepth, bitDepthValues, HDRBitDepthNames); + if (EditorGUI.EndChangeCheck()) + { + PlayerSettings.D3DHDRBitDepth = bitDepth; + } + } + } + } } EditorGUILayout.Space(); @@ -2299,16 +2322,6 @@ private static GUIContent[] GetNiceManagedStrippingLevelNames(ManagedStrippingLe return GetGUIContentsForValues(m_NiceManagedStrippingLevelNames, managedStrippingLevels); } - private void AutoAssignProperty(SerializedProperty property, string packageDir, string fileName) - { - if (property.stringValue.Length == 0 || !File.Exists(Path.Combine(packageDir, property.stringValue))) - { - string filePath = Path.Combine(packageDir, fileName); - if (File.Exists(filePath)) - property.stringValue = fileName; - } - } - public void BrowseablePathProperty(string propertyLabel, SerializedProperty property, string browsePanelTitle, string extension, string dir) { EditorGUILayout.BeginHorizontal(); @@ -2469,20 +2482,6 @@ public void PublishSectionGUI(BuildTargetGroup targetGroup, ISettingEditorExtens EndSettingsBox(); } - private static void ShowWarning(GUIContent warningMessage) - { - if (s_WarningIcon == null) - s_WarningIcon = EditorGUIUtility.LoadIcon("console.warnicon"); - - // var c = new GUIContent(error) { image = s_WarningIcon }; - warningMessage.image = s_WarningIcon; - - GUILayout.Space(5); - GUILayout.BeginVertical(EditorStyles.helpBox); - GUILayout.Label(warningMessage, EditorStyles.wordWrappedMiniLabel); - GUILayout.EndVertical(); - } - protected override bool ShouldHideOpenButton() { return true; diff --git a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsSplashScreenEditor.cs b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsSplashScreenEditor.cs index bd8995a8ca..e5457d5b0b 100644 --- a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsSplashScreenEditor.cs +++ b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsSplashScreenEditor.cs @@ -15,7 +15,6 @@ internal partial class PlayerSettingsSplashScreenEditor { PlayerSettingsEditor m_Owner; - SerializedProperty m_ResolutionDialogBanner; SerializedProperty m_ShowUnitySplashLogo; SerializedProperty m_ShowUnitySplashScreen; SerializedProperty m_SplashScreenAnimation; @@ -107,7 +106,6 @@ public PlayerSettingsSplashScreenEditor(PlayerSettingsEditor owner) public void OnEnable() { - m_ResolutionDialogBanner = m_Owner.FindPropertyAssert("resolutionDialogBanner"); m_ShowUnitySplashLogo = m_Owner.FindPropertyAssert("m_ShowUnitySplashLogo"); m_ShowUnitySplashScreen = m_Owner.FindPropertyAssert("m_ShowUnitySplashScreen"); m_SplashScreenAnimation = m_Owner.FindPropertyAssert("m_SplashScreenAnimation"); @@ -200,9 +198,11 @@ private void DrawLogoListElementCallback(Rect rect, int index, bool isActive, bo logo.objectReferenceValue = value; // Properties + var oldLabelWidth = EditorGUIUtility.labelWidth; 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"); + EditorGUIUtility.labelWidth = oldLabelWidth; EditorGUI.BeginChangeCheck(); var newDurationVal = EditorGUI.Slider(propertyRect, k_Texts.logoDuration, duration.floatValue, k_MinLogoTime, k_MaxLogoTime); @@ -297,17 +297,6 @@ public void SplashSectionGUI(BuildPlatform platform, BuildTargetGroup targetGrou { if (m_Owner.BeginSettingsBox(sectionIndex, k_Texts.title)) { - if (targetGroup == BuildTargetGroup.Standalone) - { - ObjectReferencePropertyField(m_ResolutionDialogBanner, k_Texts.configDialogBanner); - if (m_ResolutionDialogBanner.objectReferenceValue != null) - { - EditorGUILayout.HelpBox(k_Texts.configDialogBannerDeprecationWarning.text, MessageType.Warning, true); - } - - EditorGUILayout.Space(); - } - if (m_Owner.m_VRSettings.TargetGroupSupportsVirtualReality(targetGroup)) ObjectReferencePropertyField(m_VirtualRealitySplashScreen, k_Texts.vrSplashScreen); @@ -342,9 +331,12 @@ private void BuiltinCustomSplashScreenGUI() if (SplashScreen.isFinished) { SplashScreen.Begin(); - var gv = GameView.GetMainGameView(); - if (gv) - gv.Focus(); + PreviewEditorWindow.RepaintAll(); + var preview = PreviewEditorWindow.GetMainPreviewWindow(); + if (preview) + { + preview.Focus(); + } EditorApplication.update += PollSplashState; } else @@ -392,7 +384,6 @@ private void BuiltinCustomSplashScreenGUI() if (EditorGUILayout.BeginFadeGroup(m_ShowLogoControlsAnimator.faded)) { - EditorGUI.indentLevel++; EditorGUI.BeginChangeCheck(); var oldDrawmode = m_SplashScreenDrawMode.intValue; EditorGUILayout.PropertyField(m_SplashScreenDrawMode, k_Texts.drawMode); @@ -403,7 +394,6 @@ private void BuiltinCustomSplashScreenGUI() else AddUnityLogoToLogosList(); } - EditorGUI.indentLevel--; } EditorGUILayout.EndFadeGroup(); @@ -432,6 +422,9 @@ private void BuiltinCustomSplashScreenGUI() void PollSplashState() { + // Force the GameViews to repaint whilst showing the splash(1166664) + PreviewEditorWindow.RepaintAll(); + // When the splash screen is playing we need to keep track so that we can update the preview button when it has finished. if (SplashScreen.isFinished) { diff --git a/Editor/Mono/Inspector/PreviewRenderUtility.cs b/Editor/Mono/Inspector/PreviewRenderUtility.cs index 8a845b4c57..86672b6e2e 100644 --- a/Editor/Mono/Inspector/PreviewRenderUtility.cs +++ b/Editor/Mono/Inspector/PreviewRenderUtility.cs @@ -386,20 +386,6 @@ public GameObject InstantiatePrefabInScene(GameObject prefab) return instance; } - private Material GetInvisibleMaterial() - { - if (m_InvisibleMaterial == null) - { - // A material intentionally draws nothing. Used to hide submeshes we don't want users to see. - m_InvisibleMaterial = new Material(Shader.FindBuiltin("Internal-Colored.shader")); - m_InvisibleMaterial.hideFlags = HideFlags.HideAndDontSave; - m_InvisibleMaterial.SetColor("_Color", Color.clear); - m_InvisibleMaterial.SetInt("_ZWrite", 0); - } - - return m_InvisibleMaterial; - } - internal void AddManagedGO(GameObject go) { m_PreviewScene.AddManagedGO(go); diff --git a/Editor/Mono/Inspector/PrimitiveCollider3DEditor.cs b/Editor/Mono/Inspector/PrimitiveCollider3DEditor.cs deleted file mode 100644 index b51d41e92f..0000000000 --- a/Editor/Mono/Inspector/PrimitiveCollider3DEditor.cs +++ /dev/null @@ -1,63 +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 UnityEditor.IMGUI.Controls; -using UnityEngine; - -namespace UnityEditor -{ - internal abstract class PrimitiveCollider3DEditor : Collider3DEditorBase - { - protected abstract PrimitiveBoundsHandle boundsHandle { get; } - - protected abstract void CopyColliderPropertiesToHandle(); - - protected abstract void CopyHandlePropertiesToCollider(); - - protected override GUIContent editModeButton { get { return PrimitiveBoundsHandle.editModeButton; } } - - protected Vector3 InvertScaleVector(Vector3 scaleVector) - { - for (int axis = 0; axis < 3; ++axis) - scaleVector[axis] = scaleVector[axis] == 0f ? 0f : 1f / scaleVector[axis]; - return scaleVector; - } - - protected virtual void OnSceneGUI() - { - if (!editingCollider || !target) - return; - - Collider collider = (Collider)target; - - if (Mathf.Approximately(collider.transform.lossyScale.sqrMagnitude, 0f)) - return; - - // collider matrix is center multiplied by transform's matrix with custom postmultiplied lossy scale matrix - using (new Handles.DrawingScope(Matrix4x4.TRS(collider.transform.position, collider.transform.rotation, Vector3.one))) - { - CopyColliderPropertiesToHandle(); - - boundsHandle.SetColor(collider.enabled ? Handles.s_ColliderHandleColor : Handles.s_ColliderHandleColorDisabled); - EditorGUI.BeginChangeCheck(); - boundsHandle.DrawHandle(); - if (EditorGUI.EndChangeCheck()) - { - Undo.RecordObject(collider, string.Format("Modify {0}", ObjectNames.NicifyVariableName(target.GetType().Name))); - CopyHandlePropertiesToCollider(); - } - } - } - - protected Vector3 TransformColliderCenterToHandleSpace(Transform colliderTransform, Vector3 colliderCenter) - { - return Handles.inverseMatrix * (colliderTransform.localToWorldMatrix * colliderCenter); - } - - protected Vector3 TransformHandleCenterToColliderSpace(Transform colliderTransform, Vector3 handleCenter) - { - return colliderTransform.localToWorldMatrix.inverse * (Handles.matrix * handleCenter); - } - } -} diff --git a/Editor/Mono/Inspector/RayTracingShaderInspector.cs b/Editor/Mono/Inspector/RayTracingShaderInspector.cs new file mode 100644 index 0000000000..0980402cf7 --- /dev/null +++ b/Editor/Mono/Inspector/RayTracingShaderInspector.cs @@ -0,0 +1,249 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using UnityEngine; +using System.Globalization; +using UnityEngine.Experimental.Rendering; +using System.Collections.Generic; + +namespace UnityEditor +{ + [CustomEditor(typeof(RayTracingShader))] + internal class RayTracingShaderInspector : Editor + { + SerializedProperty m_MaxRecursionDepth; + + Vector2 m_ScrollPosition = Vector2.zero; + + private class Styles + { + public GUIContent s_MaxRecursionDepthText = EditorGUIUtility.TrTextContent("Max. Recursion Depth", "Limit on ray recursion for the Ray Tracing pipeline. This is defined in the shader by using max_recursion_depth pragma(e.g. \"#pragma max_recursion_depth 5\"). Applications should pick a limit that is as low as absolutely necessary. A value of 1 means that only primary rays can be cast."); + public GUIContent s_PlatformList = EditorGUIUtility.TrTextContent("Platforms:"); + public GUIContent s_NotSupported = EditorGUIUtility.TrTextContent("Ray Tracing Shader not supported! No graphics APIs with Ray Tracing support found in the Graphics APIs list."); + public GUIContent s_Index = EditorGUIUtility.TrTextContent("Index"); + public GUIContent s_Name = EditorGUIUtility.TrTextContent("Name"); + public GUIContent s_PayloadSize = EditorGUIUtility.TrTextContent("Payload Size (Bytes)"); + public GUIContent s_ParamSize = EditorGUIUtility.TrTextContent("Param. Size (Bytes)"); + public GUIContent s_RayGenShaderNames = EditorGUIUtility.TrTextContent("Ray Generation Shaders", "The list of all ray generation shaders in the shader file. Only one ray generation shader can be executed at a time."); + public GUIContent s_MissShaderNames = EditorGUIUtility.TrTextContent("Miss Shaders", "The list of all miss shaders in the shader file. The index of the miss shader to execute is specified when calling TraceRay HLSL function."); + public GUIContent s_CallableShaderNames = EditorGUIUtility.TrTextContent("Callable Shaders", "The list of all callable shaders in the shader file. The index of the callable shader to execute is specified when calling CallShader HLSL function."); + public GUIStyle s_LabelStyle = new GUIStyle(EditorStyles.boldLabel); + public Styles() + { + s_LabelStyle.richText = true; + } + } + + static Styles styles; + + static List GetPlatformList(RayTracingShader rs) + { + var platformList = new List(); + var platformCount = ShaderUtil.GetRayTracingShaderPlatformCount(rs); + for (var i = 0; i < platformCount; ++i) + { + var platform = ShaderUtil.GetRayTracingShaderPlatformType(rs, i); + if (ShaderUtil.IsRayTracingShaderValidForPlatform(rs, platform)) + platformList.Add(platform.ToString()); + } + return platformList; + } + + private bool ShowPlatformListSection(RayTracingShader rs) + { + var platformList = GetPlatformList(rs); + if (platformList.Count != 0) + { + EditorGUI.indentLevel++; + GUILayout.Label(styles.s_PlatformList); + foreach (var p in platformList) + { + EditorGUILayout.LabelField(p); + } + EditorGUI.indentLevel--; + return true; + } + return false; + } + + public void OnEnable() + { + m_MaxRecursionDepth = serializedObject.FindProperty("m_MaxRecursionDepth"); + } + + void ShowRayGenerationShaderList(string[] shaderNames) + { + GUILayout.BeginVertical(GUI.skin.box); + + for (int i = 0; i < shaderNames.Length; ++i) + { + GUILayout.Label(shaderNames[i], EditorStyles.textArea); + } + + GUILayout.EndVertical(); + } + + void ShowMissShaderList(string[] missShaderNames, int[] rayPayloadSize) + { + GUIStyle messageStyle = "CN StatusInfo"; + + float lineHeight = messageStyle.CalcHeight(EditorGUIUtility.TempContent("ShaderName"), 100); + + Rect rHeader = EditorGUILayout.GetControlRect(false, lineHeight); + + Vector2 indexColumnSize = EditorStyles.boldLabel.CalcSize(styles.s_Index); + indexColumnSize.x += 15; + GUI.Label(rHeader, styles.s_Index, new GUIStyle(EditorStyles.boldLabel)); + + rHeader.xMin += indexColumnSize.x; + GUI.Label(rHeader, styles.s_Name, EditorStyles.boldLabel); + + Vector2 payloadColumnSize = EditorStyles.boldLabel.CalcSize(styles.s_PayloadSize); + + rHeader.xMin = rHeader.xMax - payloadColumnSize.x - 15; + GUI.Label(rHeader, styles.s_PayloadSize, EditorStyles.boldLabel); + + GUILayout.BeginVertical(GUI.skin.box); + + for (int i = 0; i < missShaderNames.Length; ++i) + { + Rect r = EditorGUILayout.GetControlRect(false, lineHeight); + + GUI.Label(r, i.ToString(), EditorStyles.textArea); + + r.xMin += indexColumnSize.x; + GUI.Label(r, missShaderNames[i], EditorStyles.textArea); + + r.xMin = r.xMax - payloadColumnSize.x - 10; + GUI.Label(r, rayPayloadSize[i].ToString(), EditorStyles.textArea); + } + + GUILayout.EndVertical(); + } + + void ShowCallableShaderList(string[] callableShaderNames, int[] paramSize) + { + GUIStyle messageStyle = "CN StatusInfo"; + + float lineHeight = messageStyle.CalcHeight(EditorGUIUtility.TempContent("ShaderName"), 100); + + Rect rHeader = EditorGUILayout.GetControlRect(false, lineHeight); + + Vector2 indexColumnSize = EditorStyles.boldLabel.CalcSize(styles.s_Index); + indexColumnSize.x += 15; + GUI.Label(rHeader, styles.s_Index, EditorStyles.boldLabel); + + rHeader.xMin += indexColumnSize.x; + GUI.Label(rHeader, styles.s_Name, EditorStyles.boldLabel); + + Vector2 paramColumnSize = EditorStyles.boldLabel.CalcSize(styles.s_ParamSize); + + rHeader.xMin = rHeader.xMax - paramColumnSize.x - 15; + GUI.Label(rHeader, styles.s_ParamSize, EditorStyles.boldLabel); + + GUILayout.BeginVertical(GUI.skin.box); + + for (int i = 0; i < callableShaderNames.Length; ++i) + { + Rect r = EditorGUILayout.GetControlRect(false, lineHeight); + + GUI.Label(r, i.ToString(), EditorStyles.textArea); + + r.xMin += indexColumnSize.x; + GUI.Label(r, callableShaderNames[i], EditorStyles.textArea); + + r.xMin = r.xMax - paramColumnSize.x - 10; + GUI.Label(r, paramSize[i].ToString(), EditorStyles.textArea); + } + + GUILayout.EndVertical(); + } + + public override void OnInspectorGUI() + { + if (styles == null) + styles = new Styles(); + + var rts = target as RayTracingShader; + if (rts == null) + return; + + serializedObject.Update(); + + GUI.enabled = true; + + EditorGUI.indentLevel = 0; + + if (ShowPlatformListSection(rts)) + { + EditorGUILayout.Space(); + + EditorGUILayout.PropertyField(m_MaxRecursionDepth, styles.s_MaxRecursionDepthText); + + int rayGenShaderCount = ShaderUtil.GetRayGenerationShaderCount(rts); + if (rayGenShaderCount > 0) + { + GUILayout.Space(15.0f); + GUILayout.Label(styles.s_RayGenShaderNames, styles.s_LabelStyle); + + string[] rayGenShaderNames = new string[rayGenShaderCount]; + for (int i = 0; i < rayGenShaderCount; i++) + rayGenShaderNames[i] = ShaderUtil.GetRayGenerationShaderName(rts, i); + + ShowRayGenerationShaderList(rayGenShaderNames); + } + + int missShaderCount = ShaderUtil.GetMissShaderCount(rts); + if (missShaderCount > 0) + { + GUILayout.Space(15.0f); + + GUILayout.Label(styles.s_MissShaderNames, styles.s_LabelStyle); + + string[] missShaderNames = new string[missShaderCount]; + int[] missShaderPayloadSize = new int[missShaderCount]; + for (int i = 0; i < missShaderCount; i++) + { + missShaderNames[i] = ShaderUtil.GetMissShaderName(rts, i); + missShaderPayloadSize[i] = ShaderUtil.GetMissShaderRayPayloadSize(rts, i); + } + + ShowMissShaderList(missShaderNames, missShaderPayloadSize); + } + + int callableShaderCount = ShaderUtil.GetCallableShaderCount(rts); + if (callableShaderCount > 0) + { + GUILayout.Space(15.0f); + + GUILayout.Label(styles.s_CallableShaderNames, styles.s_LabelStyle); + + string[] callableShaderNames = new string[callableShaderCount]; + int[] callableShaderParamsSize = new int[callableShaderCount]; + for (int i = 0; i < callableShaderCount; i++) + { + callableShaderNames[i] = ShaderUtil.GetCallableShaderName(rts, i); + callableShaderParamsSize[i] = ShaderUtil.GetCallableShaderParamSize(rts, i); + } + + ShowCallableShaderList(callableShaderNames, callableShaderParamsSize); + } + } + else + { + EditorGUILayout.HelpBox(styles.s_NotSupported.text, MessageType.Error); + } + + ShowShaderErrors(rts); + } + + private void ShowShaderErrors(RayTracingShader s) + { + int n = ShaderUtil.GetRayTracingShaderMessageCount(s); + if (n < 1) + return; + ShaderInspector.ShaderErrorListUI(s, ShaderUtil.GetRayTracingShaderMessages(s), ref m_ScrollPosition); + } + } +} diff --git a/Editor/Mono/Inspector/RectHandles.cs b/Editor/Mono/Inspector/RectHandles.cs index f3f48c55d0..3bc48f50b8 100644 --- a/Editor/Mono/Inspector/RectHandles.cs +++ b/Editor/Mono/Inspector/RectHandles.cs @@ -44,16 +44,16 @@ internal static void DetectCursorChange(int id) } } - internal static Vector3 SideSlider(int id, Vector3 position, Vector3 sideVector, Vector3 direction, float size, Handles.CapFunction capFunction, float snap) + internal static Vector3 SideSlider(int id, Vector3 position, Vector3 sideVector, Vector3 direction, float size, Handles.CapFunction capFunction, Vector2 snap) { return SideSlider(id, position, sideVector, direction, size, capFunction, snap, 0); } - internal static Vector3 SideSlider(int id, Vector3 position, Vector3 sideVector, Vector3 direction, float size, Handles.CapFunction capFunction, float snap, float bias) + internal static Vector3 SideSlider(int id, Vector3 position, Vector3 sideVector, Vector3 direction, float size, Handles.CapFunction capFunction, Vector2 snap, float bias) { Event evt = Event.current; Vector3 handleDir = Vector3.Cross(sideVector, direction).normalized; - Vector3 pos = Handles.Slider2D(id, position, handleDir, direction, sideVector, 0, capFunction, Vector2.one * snap); + Vector3 pos = Handles.Slider2D(id, position, handleDir, direction, sideVector, 0, capFunction, snap); pos = position + Vector3.Project(pos - position, direction); switch (evt.type) diff --git a/Editor/Mono/Inspector/RectTransformEditor.cs b/Editor/Mono/Inspector/RectTransformEditor.cs index b004cec7bd..d96aab1259 100644 --- a/Editor/Mono/Inspector/RectTransformEditor.cs +++ b/Editor/Mono/Inspector/RectTransformEditor.cs @@ -730,7 +730,7 @@ void ParentRectPreviewDragHandles(RectTransform gui, Transform space) continue; EditorGUI.BeginChangeCheck(); - Vector3 newPos = RectHandles.SideSlider(id, curPos, sideDir, slideDir, size, null, 0, -3); + Vector3 newPos = RectHandles.SideSlider(id, curPos, sideDir, slideDir, size, null, Vector2.zero, -3); if (EditorGUI.EndChangeCheck()) { Vector2 curPosInSpace = space.InverseTransformPoint(curPos); @@ -795,7 +795,7 @@ void UpdateTemporaryRect() { s_ParentDragTime = Time.realtimeSinceStartup; Canvas.ForceUpdateCanvases(); - GameView.RepaintAll(); + PreviewEditorWindow.RepaintAll(); return; } @@ -816,7 +816,7 @@ void UpdateTemporaryRect() } Canvas.ForceUpdateCanvases(); SceneView.RepaintAll(); - GameView.RepaintAll(); + PreviewEditorWindow.RepaintAll(); } void AllAnchorsSceneGUI(RectTransform gui, RectTransform guiParent, Transform parentSpace, Transform transform) diff --git a/Editor/Mono/Inspector/RenderPipelineEditorUtility.cs b/Editor/Mono/Inspector/RenderPipelineEditorUtility.cs new file mode 100644 index 0000000000..241c0c0a52 --- /dev/null +++ b/Editor/Mono/Inspector/RenderPipelineEditorUtility.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 UnityEngine.Rendering; + +namespace UnityEditor.Rendering +{ + [AttributeUsage(AttributeTargets.Class)] + public class ScriptableRenderPipelineExtensionAttribute : Attribute + { + internal Type renderPipelineType; + + public ScriptableRenderPipelineExtensionAttribute(Type renderPipelineAsset) + { + if (!(renderPipelineAsset?.IsSubclassOf(typeof(RenderPipelineAsset)) ?? false)) + throw new ArgumentException($"Given renderPipelineAsset must derive from RenderPipelineAsset"); + renderPipelineType = renderPipelineAsset; + } + + public bool inUse + => GraphicsSettings.currentRenderPipeline?.GetType() == renderPipelineType; + } + + public static class RenderPipelineEditorUtility + { + public static Type FetchFirstCompatibleTypeUsingScriptableRenderPipelineExtension() + { + var extensionTypes = TypeCache.GetTypesDerivedFrom(); + + foreach (Type extensionType in extensionTypes) + { + ScriptableRenderPipelineExtensionAttribute attribute = Attribute.GetCustomAttribute(extensionType, typeof(ScriptableRenderPipelineExtensionAttribute)) as ScriptableRenderPipelineExtensionAttribute; + if (attribute != null && attribute.inUse) + return extensionType; + } + return null; + } + } +} diff --git a/Editor/Mono/Inspector/RendererEditorBase.cs b/Editor/Mono/Inspector/RendererEditorBase.cs index 6bb465e18b..1021ccf069 100644 --- a/Editor/Mono/Inspector/RendererEditorBase.cs +++ b/Editor/Mono/Inspector/RendererEditorBase.cs @@ -9,6 +9,7 @@ using System.Linq; using Object = UnityEngine.Object; using System.Globalization; +using UnityEngine.Experimental.Rendering; namespace UnityEditor { @@ -53,15 +54,6 @@ internal bool IsUsingLightProbeProxyVolume(int selectionCount) return isUsingLightProbeVolumes; } - internal bool HasValidLightProbeProxyVolumeOverride(Renderer renderer, int selectionCount) - { - LightProbeProxyVolume proxyVolumeOverride = (renderer.lightProbeProxyVolumeOverride != null) ? - renderer.lightProbeProxyVolumeOverride.GetComponent() : - null; - - return IsUsingLightProbeProxyVolume(selectionCount) && ((proxyVolumeOverride == null) || (proxyVolumeOverride.boundingBoxMode != LightProbeProxyVolume.BoundingBoxMode.AutomaticLocal)); - } - internal void RenderLightProbeProxyVolumeWarningNote(Renderer renderer, int selectionCount) { if (IsUsingLightProbeProxyVolume(selectionCount)) @@ -325,6 +317,7 @@ internal static string[] defaultRenderingLayerNames private SerializedProperty m_RendererPriority; private SerializedProperty m_SkinnedMotionVectors; private SerializedProperty m_MotionVectors; + private SerializedProperty m_RayTracingMode; protected SerializedProperty m_Materials; private SerializedProperty m_MaterialsSize; @@ -339,6 +332,8 @@ class Styles public static readonly GUIContent skinnedMotionVectors = EditorGUIUtility.TrTextContent("Skinned Motion Vectors", "Enabling skinned motion vectors will use double precision motion vectors for the skinned mesh. This increases accuracy of motion vectors at the cost of additional memory usage."); public static readonly GUIContent renderingLayerMask = EditorGUIUtility.TrTextContent("Rendering Layer Mask", "Mask that can be used with SRP DrawRenderers command to filter renderers outside of the normal layering system."); public static readonly GUIContent rendererPriority = EditorGUIUtility.TrTextContent("Priority", "Sets the priority value that the render pipeline uses to calculate the rendering order."); + public static readonly GUIContent rayTracingModeStyle = EditorGUIUtility.TrTextContent("Ray Tracing Mode", ""); + public static readonly GUIContent[] rayTracingModeOptions = (Enum.GetNames(typeof(RayTracingMode)).Select(x => ObjectNames.NicifyVariableName(x)).ToArray()).Select(x => new GUIContent(x)).ToArray(); } protected Probes m_Probes; @@ -355,6 +350,7 @@ public virtual void OnEnable() m_DynamicOccludee = serializedObject.FindProperty("m_DynamicOccludee"); m_RenderingLayerMask = serializedObject.FindProperty("m_RenderingLayerMask"); m_RendererPriority = serializedObject.FindProperty("m_RendererPriority"); + m_RayTracingMode = serializedObject.FindProperty("m_RayTracingMode"); m_MotionVectors = serializedObject.FindProperty("m_MotionVectors"); m_SkinnedMotionVectors = serializedObject.FindProperty("m_SkinnedMotionVectors"); m_Materials = serializedObject.FindProperty("m_Materials"); @@ -408,7 +404,7 @@ protected void Other2DSettingsGUI() EditorGUILayout.EndFoldoutHeaderGroup(); } - protected void OtherSettingsGUI(bool showMotionVectors, bool showSkinnedMotionVectors = false, bool showSortingLayerFields = false) + protected void OtherSettingsGUI(bool showMotionVectors, bool showSkinnedMotionVectors = false, bool showSortingLayerFields = false, bool showRayTracingModeField = false) { m_ShowOtherSettings.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_ShowOtherSettings.value, Styles.otherSettings); @@ -433,6 +429,9 @@ protected void OtherSettingsGUI(bool showMotionVectors, bool showSkinnedMotionVe DrawRenderingLayer(); DrawRendererPriority(m_RendererPriority); + if (showRayTracingModeField) + RenderRayTracingField(); + EditorGUI.indentLevel--; } @@ -525,6 +524,12 @@ internal static void DrawRendererPriority(SerializedProperty rendererPrority, bo } } + protected void RenderRayTracingField() + { + if (SystemInfo.supportsRayTracing) + EditorGUILayout.Popup(m_RayTracingMode, Styles.rayTracingModeOptions, Styles.rayTracingModeStyle); + } + protected void RenderCommonProbeFields(bool useMiniStyle) { bool isDeferredRenderingPath = SceneView.IsUsingDeferredRenderingPath(); diff --git a/Editor/Mono/Inspector/SkinnedMeshRendererEditor.cs b/Editor/Mono/Inspector/SkinnedMeshRendererEditor.cs index c5bb86407c..0c0ee28acf 100644 --- a/Editor/Mono/Inspector/SkinnedMeshRendererEditor.cs +++ b/Editor/Mono/Inspector/SkinnedMeshRendererEditor.cs @@ -17,6 +17,7 @@ internal class SkinnedMeshRendererEditor : RendererEditorBase class Styles { public static readonly GUIContent legacyClampBlendShapeWeightsInfo = EditorGUIUtility.TrTextContent("Note that BlendShape weight range is clamped. This can be disabled in Player Settings."); + public static readonly GUIContent meshNotSupportingSkinningInfo = EditorGUIUtility.TrTextContent("The assigned mesh doesn't support skinning. A valid setup requires bone weights with bind pose or blend shapes. If you do not need either of these, use a MeshRenderer instead."); public static readonly GUIContent bounds = EditorGUIUtility.TrTextContent("Bounds"); public static readonly GUIContent quality = EditorGUIUtility.TrTextContent("Quality", "Number of bones to use per vertex during skinning."); public static readonly GUIContent updateWhenOffscreen = EditorGUIUtility.TrTextContent("Update When Offscreen", "If an accurate bounding volume representation should be calculated every frame. "); @@ -69,7 +70,9 @@ public override void OnInspectorGUI() EditorGUILayout.PropertyField(m_Quality, Styles.quality); EditorGUILayout.PropertyField(m_UpdateWhenOffscreen, Styles.updateWhenOffscreen); - EditorGUILayout.PropertyField(m_Mesh, Styles.mesh); + + OnMeshUI(); + EditorGUILayout.PropertyField(m_RootBone, Styles.rootBone); DrawMaterials(); @@ -84,6 +87,23 @@ internal override Bounds GetWorldBoundsOfTarget(Object targetObject) return ((SkinnedMeshRenderer)targetObject).bounds; } + public void OnMeshUI() + { + SkinnedMeshRenderer renderer = (SkinnedMeshRenderer)target; + + if (renderer.sharedMesh != null) + { + bool haveClothComponent = renderer.gameObject.GetComponent() != null; + + if (!haveClothComponent && renderer.sharedMesh.blendShapeCount == 0 && (renderer.sharedMesh.boneWeights.Length == 0 || renderer.sharedMesh.bindposes.Length == 0)) + { + EditorGUILayout.HelpBox(Styles.meshNotSupportingSkinningInfo.text, MessageType.Info); + } + } + + EditorGUILayout.PropertyField(m_Mesh, Styles.mesh); + } + public void OnBlendShapeUI() { SkinnedMeshRenderer renderer = (SkinnedMeshRenderer)target; diff --git a/Editor/Mono/Inspector/SphereColliderEditor.cs b/Editor/Mono/Inspector/SphereColliderEditor.cs index c178da3b70..f6e0df09cf 100644 --- a/Editor/Mono/Inspector/SphereColliderEditor.cs +++ b/Editor/Mono/Inspector/SphereColliderEditor.cs @@ -2,18 +2,53 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License +using UnityEditor.EditorTools; using UnityEditor.IMGUI.Controls; using UnityEngine; namespace UnityEditor { + [EditorTool("Edit Sphere Collider", typeof(SphereCollider))] + class SphereColliderTool : PrimitiveColliderTool + { + readonly SphereBoundsHandle m_BoundsHandle = new SphereBoundsHandle(); + + protected override PrimitiveBoundsHandle boundsHandle + { + get { return m_BoundsHandle; } + } + + protected override void CopyColliderPropertiesToHandle(SphereCollider collider) + { + m_BoundsHandle.center = TransformColliderCenterToHandleSpace(collider.transform, collider.center); + m_BoundsHandle.radius = collider.radius * GetRadiusScaleFactor(collider); + } + + protected override void CopyHandlePropertiesToCollider(SphereCollider collider) + { + collider.center = TransformHandleCenterToColliderSpace(collider.transform, m_BoundsHandle.center); + float scaleFactor = GetRadiusScaleFactor(collider); + collider.radius = Mathf.Approximately(scaleFactor, 0f) ? 0f : m_BoundsHandle.radius / scaleFactor; + } + + static float GetRadiusScaleFactor(SphereCollider collider) + { + float result = 0f; + Vector3 lossyScale = collider.transform.lossyScale; + + for (int axis = 0; axis < 3; ++axis) + result = Mathf.Max(result, Mathf.Abs(lossyScale[axis])); + + return result; + } + } + [CustomEditor(typeof(SphereCollider))] [CanEditMultipleObjects] - internal class SphereColliderEditor : PrimitiveCollider3DEditor + class SphereColliderEditor : Collider3DEditorBase { SerializedProperty m_Center; SerializedProperty m_Radius; - private readonly SphereBoundsHandle m_BoundsHandle = new SphereBoundsHandle(); public override void OnEnable() { @@ -27,7 +62,8 @@ public override void OnInspectorGUI() { serializedObject.Update(); - InspectorEditButtonGUI(); + EditorGUILayout.EditorToolbarForTarget(EditorGUIUtility.TrTempContent("Edit Collider"), target); + EditorGUILayout.PropertyField(m_IsTrigger); EditorGUILayout.PropertyField(m_Material); EditorGUILayout.PropertyField(m_Center); @@ -35,34 +71,5 @@ public override void OnInspectorGUI() serializedObject.ApplyModifiedProperties(); } - - protected override PrimitiveBoundsHandle boundsHandle { get { return m_BoundsHandle; } } - - protected override void CopyColliderPropertiesToHandle() - { - SphereCollider collider = (SphereCollider)target; - m_BoundsHandle.center = TransformColliderCenterToHandleSpace(collider.transform, collider.center); - m_BoundsHandle.radius = collider.radius * GetRadiusScaleFactor(); - } - - protected override void CopyHandlePropertiesToCollider() - { - SphereCollider collider = (SphereCollider)target; - collider.center = TransformHandleCenterToColliderSpace(collider.transform, m_BoundsHandle.center); - float scaleFactor = GetRadiusScaleFactor(); - collider.radius = - Mathf.Approximately(scaleFactor, 0f) ? 0f : m_BoundsHandle.radius / GetRadiusScaleFactor(); - } - - private float GetRadiusScaleFactor() - { - float result = 0f; - Vector3 lossyScale = ((SphereCollider)target).transform.lossyScale; - for (int axis = 0; axis < 3; ++axis) - { - result = Mathf.Max(result, Mathf.Abs(lossyScale[axis])); - } - return result; - } } } diff --git a/Editor/Mono/Inspector/SpriteFrameInspector.cs b/Editor/Mono/Inspector/SpriteFrameInspector.cs index b6dbced72b..6b6d909d8c 100644 --- a/Editor/Mono/Inspector/SpriteFrameInspector.cs +++ b/Editor/Mono/Inspector/SpriteFrameInspector.cs @@ -5,8 +5,7 @@ using Unity.Collections; using UnityEditorInternal; using UnityEngine; -using UnityEngine.Experimental.U2D; -using UnityEditor.Experimental.U2D; +using UnityEngine.U2D; using UnityEngine.Rendering; using UnityEngine.Experimental.Rendering; diff --git a/Editor/Mono/Inspector/TextureInspector.cs b/Editor/Mono/Inspector/TextureInspector.cs index 9052b92e3b..338b561fe0 100644 --- a/Editor/Mono/Inspector/TextureInspector.cs +++ b/Editor/Mono/Inspector/TextureInspector.cs @@ -755,7 +755,7 @@ public override Texture2D RenderStaticPreview(string assetPath, Object[] subAsse width, height, 0, SystemInfo.GetGraphicsFormat(DefaultFormat.LDR)); - Material mat = EditorGUI.GetMaterialForSpecialTexture(texture); + Material mat = EditorGUI.GetMaterialForSpecialTexture(texture, null, QualitySettings.activeColorSpace == ColorSpace.Linear); if (mat != null) Graphics.Blit(texture, tmp, mat); else Graphics.Blit(texture, tmp); @@ -781,11 +781,6 @@ public override Texture2D RenderStaticPreview(string assetPath, Object[] subAsse return copy; } - float Log2(float x) - { - return (float)(System.Math.Log(x) / System.Math.Log(2)); - } - public override string GetInfoString() { // TextureInspector code is reused for RenderTexture and Cubemap inspectors. diff --git a/Editor/Mono/InternalEditorUtility.bindings.cs b/Editor/Mono/InternalEditorUtility.bindings.cs index 2b411328eb..e99cce90f8 100644 --- a/Editor/Mono/InternalEditorUtility.bindings.cs +++ b/Editor/Mono/InternalEditorUtility.bindings.cs @@ -45,7 +45,6 @@ public enum DllType [NativeHeader("Modules/AssetDatabase/Editor/Public/AssetDatabase.h")] [NativeHeader("Modules/AssetDatabase/Editor/Public/AssetDatabaseDeprecated.h")] [NativeHeader("Editor/Src/AssetPipeline/TextureImporting/BumpMapSettings.h")] - [NativeHeader("Editor/Src/AssetPipeline/MdFourGenerator.h")] [NativeHeader("Editor/Src/ScriptCompilation/PrecompiledAssemblies.h")] [NativeHeader("Editor/Src/AssetPipeline/ObjectHashGenerator.h")] [NativeHeader("Editor/Src/AssetPipeline/UnityExtensions.h")] @@ -129,6 +128,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); @@ -400,6 +403,12 @@ extern public static string unityPreferencesFolder get; } + internal static extern string userAppDataFolder + { + [FreeFunction("GetUserAppDataFolder")] + get; + } + [FreeFunction] extern public static string GetAssetsFolder(); @@ -718,9 +727,9 @@ private static Bounds GetLocalBounds(GameObject gameObject) { return ((SpriteMask)renderer).GetSpriteBounds(); } - if (renderer is UnityEngine.Experimental.U2D.SpriteShapeRenderer) + if (renderer is UnityEngine.U2D.SpriteShapeRenderer) { - return ((UnityEngine.Experimental.U2D.SpriteShapeRenderer)renderer).GetLocalAABB(); + return ((UnityEngine.U2D.SpriteShapeRenderer)renderer).GetLocalAABB(); } if (renderer is UnityEngine.Tilemaps.TilemapRenderer) { @@ -737,10 +746,13 @@ private static Bounds GetLocalBounds(GameObject gameObject) [FreeFunction("OpenScriptFile")] extern public static bool OpenFileAtLineExternal(string filename, int line, int column); - [Obsolete("Use CodeEditorUtility.Editor.Current.OpenProject()", false)] public static bool OpenFileAtLineExternal(string filename, int line) { - return CodeEditor.Editor.Current.OpenProject(filename, line); + if (!CodeEditor.Editor.Current.OpenProject(filename, line)) + { + return OpenFileAtLineExternal(filename, line, 0); + } + return true; } [FreeFunction("AssetDatabaseDeprecated::CanConnectToCacheServer")] diff --git a/Editor/Mono/InternalEditorUtility.cs b/Editor/Mono/InternalEditorUtility.cs index 1af8c8dd18..0a1e272ff0 100644 --- a/Editor/Mono/InternalEditorUtility.cs +++ b/Editor/Mono/InternalEditorUtility.cs @@ -424,10 +424,10 @@ internal static string[] GetCompilationDefines(EditorScriptCompilationOptions op public static void SetShowGizmos(bool value) { - GameView view = GameView.GetMainGameView(); + var view = PreviewEditorWindow.GetMainPreviewWindow(); if (view == null) - view = GameView.GetRenderingGameView(); + view = PreviewEditorWindow.GetRenderingPreview(); if (view == null) return; diff --git a/Editor/Mono/JSProxy/PreviewGenerator.cs b/Editor/Mono/JSProxy/PreviewGenerator.cs index edec441abe..5d851b96d1 100644 --- a/Editor/Mono/JSProxy/PreviewGenerator.cs +++ b/Editor/Mono/JSProxy/PreviewGenerator.cs @@ -3,16 +3,11 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using UnityEngine; -using UnityEditor; -using System; -using System.Collections; namespace UnityEditor.Web { internal class PreviewGenerator { - const string kPreviewBuildFolder = "builds"; - static protected PreviewGenerator s_Instance = null; public static PreviewGenerator GetInstance() diff --git a/Editor/Mono/Modules/DefaultBuildPostprocessor.cs b/Editor/Mono/Modules/DefaultBuildPostprocessor.cs index abd2397e52..d15f73d6ff 100644 --- a/Editor/Mono/Modules/DefaultBuildPostprocessor.cs +++ b/Editor/Mono/Modules/DefaultBuildPostprocessor.cs @@ -45,6 +45,11 @@ public virtual bool SupportsLz4Compression() return false; } + public virtual Compression GetDefaultCompression() + { + return Compression.None; + } + public virtual bool SupportsScriptsOnlyBuild() { return true; @@ -93,6 +98,14 @@ public virtual void UpdateBootConfig(BuildTarget target, BootConfigData config, if (PlayerSettings.gcIncremental) config.Set("gc-max-time-slice", "3"); } + + if ((options & BuildOptions.Development) != 0) + { + if ((options & BuildOptions.EnableDeepProfilingSupport) != 0) + { + config.Set("profiler-enable-deep-profiling-support", "1"); + } + } } public virtual string GetExtension(BuildTarget target, BuildOptions options) diff --git a/Editor/Mono/Modules/ModuleManager.cs b/Editor/Mono/Modules/ModuleManager.cs index 615e2ff22b..28ebb3b3ed 100644 --- a/Editor/Mono/Modules/ModuleManager.cs +++ b/Editor/Mono/Modules/ModuleManager.cs @@ -327,16 +327,8 @@ static bool TryParseBuildTarget(string targetString, out BuildTargetGroup buildT target = BuildTarget.StandaloneWindows; try { - if (targetString == BuildTargetGroup.Facebook.ToString()) - { - buildTargetGroup = BuildTargetGroup.Facebook; - target = BuildTarget.StandaloneWindows; - } - else - { - target = (BuildTarget)Enum.Parse(typeof(BuildTarget), targetString); - buildTargetGroup = BuildPipeline.GetBuildTargetGroup(target); - } + target = (BuildTarget)Enum.Parse(typeof(BuildTarget), targetString); + buildTargetGroup = BuildPipeline.GetBuildTargetGroup(target); return true; } catch diff --git a/Editor/Mono/Modules/PlatformSupportModule.cs b/Editor/Mono/Modules/PlatformSupportModule.cs index 48afb817d6..d399afc71c 100644 --- a/Editor/Mono/Modules/PlatformSupportModule.cs +++ b/Editor/Mono/Modules/PlatformSupportModule.cs @@ -138,6 +138,8 @@ internal interface IBuildPostprocessor bool SupportsLz4Compression(); + Compression GetDefaultCompression(); + bool SupportsScriptsOnlyBuild(); // This is the place to make sure platform has everything it needs for the build. diff --git a/Editor/Mono/Networking/PlayerConnection/AttachToPlayerGUI.cs b/Editor/Mono/Networking/PlayerConnection/AttachToPlayerGUI.cs index 5d7a6accd4..5e5029208d 100644 --- a/Editor/Mono/Networking/PlayerConnection/AttachToPlayerGUI.cs +++ b/Editor/Mono/Networking/PlayerConnection/AttachToPlayerGUI.cs @@ -18,15 +18,29 @@ internal interface IConnectionStateInternal : IConnectionState { EditorWindow parentWindow { get; } GUIContent notificationMessage { get; } + bool deepProfilingSupported { get; } void AddItemsToMenu(GenericMenu menu, Rect position); } + internal enum EditorConnectionTarget + { + None, + MainEditorProcessPlaymode, + MainEditorProcessEditmode, + // add out-off-process player/profiler here + } + public static partial class EditorGUIUtility { public static IConnectionState GetAttachToPlayerState(EditorWindow parentWindow, Action connectedCallback = null) { return new GeneralConnectionState(parentWindow, connectedCallback); } + + internal static IConnectionState GetAttachToPlayerState(EditorWindow parentWindow, Action editorModeTargetSwitchedCallback, Func editorModeTargetConnectionStatus, Action connectedCallback = null) + { + return new GeneralConnectionState(parentWindow, connectedCallback, editorModeTargetSwitchedCallback, editorModeTargetConnectionStatus); + } } static class Styles { @@ -79,6 +93,8 @@ internal class GeneralConnectionState : IConnectionStateInternal { static class Content { + public static readonly GUIContent Playmode = UnityEditor.EditorGUIUtility.TrTextContent("Playmode"); + public static readonly GUIContent Editmode = UnityEditor.EditorGUIUtility.TrTextContent("Editor"); 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)"); @@ -94,18 +110,41 @@ static class Content const int PLAYER_DIRECT_IP_CONNECT_GUID = 0xFEED; // keep this constant in sync with PLAYER_DIRECT_URL_CONNECT_GUID in GeneralConnection.h const int PLAYER_DIRECT_URL_CONNECT_GUID = 0xFEEE; + const string k_EditorConnectionName = "Editor"; public EditorWindow parentWindow { get; private set; } public ConnectionTarget connectedToTarget => ProfilerDriver.IsConnectionEditor() ? ConnectionTarget.Editor : ConnectionTarget.Player; - public string connectionName => ProfilerDriver.GetConnectionIdentifier(ProfilerDriver.connectedProfiler); + public string connectionName + { + get + { + string name = ProfilerDriver.GetConnectionIdentifier(ProfilerDriver.connectedProfiler); + if (m_EditorModeTargetState.HasValue && name.Contains(k_EditorConnectionName)) + { + if (m_EditorModeTargetConnectionStatus(EditorConnectionTarget.MainEditorProcessEditmode)) + name = Content.Editmode.text; + else + name = Content.Playmode.text; + } + return name; + } + } + + public bool deepProfilingSupported => ProfilerDriver.IsDeepProfilingSupported(ProfilerDriver.connectedProfiler); + + event Action connected; + + + event Action switchedEditorModeTarget; + Func m_EditorModeTargetConnectionStatus; + EditorConnectionTarget? m_EditorModeTargetState = null; - private event Action connected; static List s_AllGeneralAttachToPlayerStates = new List(); - public GeneralConnectionState(EditorWindow parentWindow, Action connectedCallback = null) + public GeneralConnectionState(EditorWindow parentWindow, Action connectedCallback = null, Action editorModeTargetSwitchedCallback = null, Func editorModeTargetConnectionStatus = null) { this.parentWindow = parentWindow; if (parentWindow != null) @@ -114,10 +153,18 @@ public GeneralConnectionState(EditorWindow parentWindow, Action connecte if (connectedCallback != null) connected += connectedCallback; + if (editorModeTargetSwitchedCallback != null) + { + Debug.Assert(editorModeTargetConnectionStatus != null, $"{nameof(editorModeTargetConnectionStatus)} can't be null when a {nameof(editorModeTargetSwitchedCallback)} is provided."); + switchedEditorModeTarget += editorModeTargetSwitchedCallback; + m_EditorModeTargetConnectionStatus = editorModeTargetConnectionStatus; + m_EditorModeTargetState = EditorConnectionTarget.None; + } + s_AllGeneralAttachToPlayerStates.Add(new WeakReference(this)); } - static void SuccesfullyConnectedToPlayer(string player) + static void SuccesfullyConnectedToPlayer(string player, EditorConnectionTarget? editorConnectionTarget = null) { for (int i = s_AllGeneralAttachToPlayerStates.Count - 1; i >= 0; i--) { @@ -125,7 +172,25 @@ static void SuccesfullyConnectedToPlayer(string player) { s_AllGeneralAttachToPlayerStates.RemoveAt(i); } - (s_AllGeneralAttachToPlayerStates[i].Target as GeneralConnectionState).connected?.Invoke(player); + var generalConnectionState = (s_AllGeneralAttachToPlayerStates[i].Target as GeneralConnectionState); + generalConnectionState.connected?.Invoke(player); + if (editorConnectionTarget.HasValue) + { + generalConnectionState.switchedEditorModeTarget?.Invoke(editorConnectionTarget.Value); + } + else + { + if (player.Contains(k_EditorConnectionName)) + { + // if e.g. the console or the memory profiler connects to the Editor, the profiler should switch to PlayMode profiling, not to Editmode profiling + // especially since falling back onto the Editor is the default. + generalConnectionState.switchedEditorModeTarget?.Invoke(EditorConnectionTarget.MainEditorProcessPlaymode); + } + else + { + generalConnectionState.switchedEditorModeTarget?.Invoke(EditorConnectionTarget.None); + } + } } } @@ -198,11 +263,29 @@ void AddAvailablePlayerConnections(GenericMenu menuOptions, ref bool hasOpenConn name += Content.VersionMismatch; } if (enabled) - menuOptions.AddItem(new GUIContent(name), isConnected, () => + { + if (m_EditorModeTargetState.HasValue && name.Contains(k_EditorConnectionName)) { - ProfilerDriver.connectedProfiler = guid; - SuccesfullyConnectedToPlayer(connectionName); - }); + menuOptions.AddItem(Content.Playmode, isConnected && m_EditorModeTargetConnectionStatus(EditorConnectionTarget.MainEditorProcessPlaymode), () => + { + ProfilerDriver.connectedProfiler = guid; + SuccesfullyConnectedToPlayer(connectionName, EditorConnectionTarget.MainEditorProcessPlaymode); + }); + menuOptions.AddItem(Content.Editmode, isConnected && m_EditorModeTargetConnectionStatus(EditorConnectionTarget.MainEditorProcessEditmode), () => + { + ProfilerDriver.connectedProfiler = guid; + SuccesfullyConnectedToPlayer(connectionName, EditorConnectionTarget.MainEditorProcessEditmode); + }); + } + else + { + menuOptions.AddItem(new GUIContent(name), isConnected, () => + { + 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 0e87e080cd..24dcfd1477 100644 --- a/Editor/Mono/Networking/PlayerConnection/EditorConnection.cs +++ b/Editor/Mono/Networking/PlayerConnection/EditorConnection.cs @@ -150,7 +150,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); @@ -161,6 +161,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/ObjectListArea.cs b/Editor/Mono/ObjectListArea.cs index 795649df20..7f754cccc6 100644 --- a/Editor/Mono/ObjectListArea.cs +++ b/Editor/Mono/ObjectListArea.cs @@ -7,9 +7,6 @@ using System.Collections.Generic; using System.Linq; using UnityEditorInternal; -using UnityEngine.Assertions; -using Math = System.Math; -using IndexOutOfRangeException = System.IndexOutOfRangeException; namespace UnityEditor { @@ -122,10 +119,6 @@ static GUIStyle GetStyle(string styleName) Vector2 m_LastScrollPosition = new Vector2(0, 0); double LastScrollTime = 0; - - const double kDelayQueryAfterScroll = 0.0; - - public bool selectedAssetStoreAsset; @@ -603,18 +596,6 @@ public int numItemsDisplayed get { return m_LocalAssets.ItemCount; } } - static string CreateFilterString(string searchString, string requiredClassName) - { - string filter = searchString; - - if (!string.IsNullOrEmpty(requiredClassName)) - { - filter += " t:" + requiredClassName; - } - - return filter; - } - bool ObjectsHaveThumbnails(HierarchyType type, SearchFilter searchFilter) { // Check if we have any built-ins, if so we have thumbs since all builtins have thumbs diff --git a/Editor/Mono/ObjectListGroup.cs b/Editor/Mono/ObjectListGroup.cs index 62b19915ce..fea946f05b 100644 --- a/Editor/Mono/ObjectListGroup.cs +++ b/Editor/Mono/ObjectListGroup.cs @@ -3,14 +3,7 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using UnityEngine; -using UnityEditor; -using UnityEditorInternal; -using System.Collections; -using System.Collections.Generic; -using System.Linq; using Math = System.Math; -using IndexOutOfRangeException = System.IndexOutOfRangeException; - namespace UnityEditor { @@ -258,26 +251,6 @@ protected void DrawItemCount(Rect rect) rect.y += 2; // better y pos for minilabel GUI.Label(rect, label, s_Styles.groupHeaderLabelCount); } - - Object[] GetSelectedReferences() - { - return Selection.objects; - } - - static string[] GetMainSelectedPaths() - { - List paths = new List(); - foreach (int instanceID in Selection.instanceIDs) - { - if (AssetDatabase.IsMainAsset(instanceID)) - { - string path = AssetDatabase.GetAssetPath(instanceID); - paths.Add(path); - } - } - - return paths.ToArray(); - } } } } // namespace UnityEditor diff --git a/Editor/Mono/ObjectListLocalGroup.cs b/Editor/Mono/ObjectListLocalGroup.cs index 66ca549314..0fbb018377 100644 --- a/Editor/Mono/ObjectListLocalGroup.cs +++ b/Editor/Mono/ObjectListLocalGroup.cs @@ -721,10 +721,17 @@ void DrawItem(Rect position, FilteredHierarchy.FilterResult filterItem, BuiltinR m_Content.text = labeltext; m_Content.image = null; - Texture2D icon = filterItem != null ? filterItem.icon : AssetPreview.GetAssetPreview(instanceID, m_Owner.GetAssetPreviewManagerID()); + Texture2D icon; - if (icon == null && m_Owner.GetCreateAssetUtility().icon != null) + if (m_Owner.GetCreateAssetUtility().instanceID == instanceID && m_Owner.GetCreateAssetUtility().icon != null) + { + // If we are creating a new asset we might have an icon to use icon = m_Owner.GetCreateAssetUtility().icon; + } + else + { + icon = filterItem != null ? filterItem.icon : AssetPreview.GetAssetPreview(instanceID, m_Owner.GetAssetPreviewManagerID()); + } if (selected) s_Styles.resultsLabel.Draw(position, GUIContent.none, false, false, selected, m_Owner.HasFocus()); @@ -830,6 +837,9 @@ void DrawItem(Rect position, FilteredHierarchy.FilterResult filterItem, BuiltinR s_Styles.resultsLabel.Draw(new Rect(labelRect.x - 10, labelRect.y, labelRect.width + 20, labelRect.height), GUIContent.none, true, true, false, false); labeltext = m_Owner.GetCroppedLabelText(instanceID, labeltext, position.width); + var labelNewRect = s_Styles.resultsGridLabel.CalcSizeWithConstraints(GUIContent.Temp(labeltext), position.size); + labelRect.x = position.x + (position.width - labelNewRect.x) / 2.0f; + labelRect.width = labelNewRect.x; s_Styles.resultsGridLabel.Draw(labelRect, labeltext, false, false, selected, m_Owner.HasFocus()); } diff --git a/Editor/Mono/ObjectNames.cs b/Editor/Mono/ObjectNames.cs index 94e61054db..da77edc91b 100644 --- a/Editor/Mono/ObjectNames.cs +++ b/Editor/Mono/ObjectNames.cs @@ -3,6 +3,9 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; +using System.Collections.Generic; +using System.Linq; +using JetBrains.Annotations; using UnityEngine; using Object = UnityEngine.Object; @@ -10,12 +13,43 @@ namespace UnityEditor { public sealed partial class ObjectNames { - // *undocumented* - private static string GetObjectTypeName(Object o) + static class InspectorTitles { - if (o == null) - return "Nothing Selected"; + static readonly Dictionary s_InspectorTitles; + static InspectorTitles() + { + var addComponentMenuTypes = TypeCache.GetTypesWithAttribute(); + + s_InspectorTitles = new Dictionary(addComponentMenuTypes.Count); + + foreach (var type in addComponentMenuTypes) + { + var attr = type.GetCustomAttributes(typeof(AddComponentMenu), false).FirstOrDefault() + as AddComponentMenu; + if (attr == null) + continue; + var title = attr.componentMenu?.Trim(); + if (string.IsNullOrEmpty(title)) + continue; + var lastPathCharIndex = title.LastIndexOf('/'); + if (lastPathCharIndex >= 0 && lastPathCharIndex < title.Length - 1) + title = title.Substring(lastPathCharIndex + 1); + else + continue; + + s_InspectorTitles[type] = title; + } + } + + public static bool TryGet(Type objectType, out string title) + { + return s_InspectorTitles.TryGetValue(objectType, out title); + } + } + + private static string GetObjectTypeName([NotNull] Object o) + { if (o is GameObject) return o.name; @@ -38,7 +72,7 @@ private static string GetObjectTypeName(Object o) if (meshfilter) { var mesh = meshfilter.sharedMesh; - return (mesh ? mesh.name : "[none]") + " (MeshFilter)"; + return (mesh ? mesh.name : L10n.Tr("[none]")) + " (MeshFilter)"; } return o.GetType().Name; @@ -76,7 +110,9 @@ public static string GetInspectorTitle(Object obj) if (obj == null) return L10n.Tr("Nothing Selected"); - var title = ObjectNames.NicifyVariableName(GetObjectTypeName(obj)); + string title; + if (!InspectorTitles.TryGet(obj.GetType(), out title)) + title = NicifyVariableName(GetObjectTypeName(obj)); if (Attribute.IsDefined(obj.GetType(), typeof(ObsoleteAttribute))) title += L10n.Tr(" (Deprecated)"); diff --git a/Editor/Mono/PackageUtility.bindings.cs b/Editor/Mono/PackageUtility.bindings.cs index 4118b4bcba..894406cdd4 100644 --- a/Editor/Mono/PackageUtility.bindings.cs +++ b/Editor/Mono/PackageUtility.bindings.cs @@ -62,12 +62,12 @@ 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, out string packageManagerDependenciesPath); + public static extern ImportPackageItem[] ExtractAndPrepareAssetList(string packagePath, out string packageIconPath, out string packageManagerDependenciesPath); [FreeFunction("DelayedImportPackageAssets")] - public static extern void ImportPackageAssets(string packageName, ImportPackageItem[] items, bool performReInstall); + public static extern void ImportPackageAssets(string packageName, ImportPackageItem[] items); [FreeFunction("ImportPackageAssets")] - public static extern void ImportPackageAssetsImmediately(string packageName, ImportPackageItem[] items, bool performReInstall); + public static extern void ImportPackageAssetsImmediately(string packageName, ImportPackageItem[] items); [FreeFunction("ImportPackageCancelledGUI")] public static extern void ImportPackageAssetsCancelledFromGUI(string packageName, ImportPackageItem[] items); diff --git a/Editor/Mono/PerceptionRemoting/HolographicEmulation/HolographicEmulationWindow.cs b/Editor/Mono/PerceptionRemoting/HolographicEmulation/HolographicEmulationWindow.cs index 98b52506b1..f5725033e8 100644 --- a/Editor/Mono/PerceptionRemoting/HolographicEmulation/HolographicEmulationWindow.cs +++ b/Editor/Mono/PerceptionRemoting/HolographicEmulation/HolographicEmulationWindow.cs @@ -31,7 +31,7 @@ internal class HolographicEmulationWindow : EditorWindow [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] @@ -97,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() @@ -110,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) @@ -130,49 +129,6 @@ 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() { PerceptionRemoting.SetVideoEncodingParameters(m_MaxBitrateKbps); @@ -341,10 +297,13 @@ 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(); + HolographicAutomation.SetEmulationMode(m_Mode); } } diff --git a/Editor/Mono/PerformanceTools/FrameDebugger.cs b/Editor/Mono/PerformanceTools/FrameDebugger.cs index a1e93c80fb..3692849c32 100644 --- a/Editor/Mono/PerformanceTools/FrameDebugger.cs +++ b/Editor/Mono/PerformanceTools/FrameDebugger.cs @@ -9,6 +9,7 @@ using System.Text; using UnityEngine; using UnityEngine.Rendering; +using UnityEditor.Rendering; using UnityEditorInternal; using System.Runtime.InteropServices; using UnityEditor.IMGUI.Controls; @@ -277,11 +278,9 @@ private struct EventDataStrings public string[] texturePropertyTooltips; } - const float kScrollbarWidth = 16; const float kResizerWidth = 5f; const float kMinListWidth = 200f; const float kMinDetailsWidth = 200f; - const float kMinWindowWidth = 240f; const float kDetailsMargin = 0f; const float kMinPreviewSize = 64f; @@ -294,7 +293,7 @@ private struct EventDataStrings const float kArrayValuePopupBtnWidth = 25.0f; // See the comments for BaseParamInfo in FrameDebuggerInternal.h - const int kShaderTypeBits = 6; + const int kShaderTypeBits = (int)ShaderType.Count; const int kArraySizeBitMask = 0x3FF; // Sometimes when disabling the frame debugger, the UI does not update automatically - @@ -486,10 +485,10 @@ private void ClickEnableFrameDebugger() // Make sure game view is visible when enabling frame debugger locally if (FrameDebuggerUtility.IsLocalEnabled()) { - GameView gameView = (GameView)WindowLayout.FindEditorWindowOfType(typeof(GameView)); - if (gameView) + var previewWindow = PreviewEditorWindow.GetMainPreviewWindow(); + if (previewWindow) { - gameView.ShowTab(); + previewWindow.ShowTab(); } } @@ -658,7 +657,7 @@ private bool DrawToolbar(FrameDebuggerEvent[] descs) int newLimit; using (new EditorGUI.DisabledScope(FrameDebuggerUtility.count <= 1)) { - newLimit = EditorGUILayout.IntSlider(FrameDebuggerUtility.limit, 1, FrameDebuggerUtility.count, -1, + newLimit = EditorGUILayout.IntSlider(FrameDebuggerUtility.limit, 1, FrameDebuggerUtility.count, 1, EditorStyles.toolbarSlider); } if (EditorGUI.EndChangeCheck()) diff --git a/Editor/Mono/PlayerSettings.bindings.cs b/Editor/Mono/PlayerSettings.bindings.cs index 7e581801d4..c2ad8e3daa 100644 --- a/Editor/Mono/PlayerSettings.bindings.cs +++ b/Editor/Mono/PlayerSettings.bindings.cs @@ -7,11 +7,12 @@ using UnityEditor.Build; using UnityEngine; using UnityEngine.Bindings; +using UnityEditor.Modules; namespace UnityEditor { // Resolution dialog setting - [Obsolete("ResolutionDialogSetting is deprecated and will be removed in future versions.", false)] + [Obsolete("The Display Resolution Dialog has been removed.", false)] public enum ResolutionDialogSetting { // Never show the resolutions dialog. @@ -438,7 +439,7 @@ public static Guid productGUID public static extern int defaultWebScreenHeight { get; set; } // Defines the behaviour of the Resolution Dialog on product launch. - [Obsolete("displayResolutionDialog is deprecated and will be removed in future versions.", false)] + [Obsolete("displayResolutionDialog has been removed.", false)] public static extern ResolutionDialogSetting displayResolutionDialog { get; set; } // Returns whether or not the specified aspect ratio is enabled. @@ -514,6 +515,10 @@ public static bool singlePassStereoRendering [NativeProperty(TargetType = TargetType.Field)] public static extern bool useHDRDisplay { get; set; } + [NativeProperty(TargetType = TargetType.Field)] + public static extern D3DHDRDisplayBitDepth D3DHDRBitDepth { get; set; } + + // What happens with the fullscreen Window when it runs in the background public static extern bool visibleInBackground { get; set; } @@ -558,7 +563,7 @@ public static extern bool openGLRequireES32 } // The image to display in the Resolution Dialog window. - [Obsolete("resolutionDialogBanner is deprecated and will be removed in future versions.", false)] + [Obsolete("resolutionDialogBanner has been removed.", false)] public static extern Texture2D resolutionDialogBanner { get; set; } // The image to display on the Virtual Reality splash screen. @@ -765,8 +770,21 @@ public static void SetScriptingDefineSymbolsForGroup(BuildTargetGroup targetGrou [FreeFunction("GetDefaultScriptingBackendForGroup")] public static extern ScriptingImplementation GetDefaultScriptingBackend(BuildTargetGroup targetGroup); + public static void SetIl2CppCompilerConfiguration(BuildTargetGroup targetGroup, Il2CppCompilerConfiguration configuration) + { + var scriptingImpl = ModuleManager.GetScriptingImplementations(targetGroup); + if (scriptingImpl != null && !scriptingImpl.AllowIL2CPPCompilerConfigurationSelection()) + { + Debug.LogWarning($"The C++ compiler configuration option does not apply to the {targetGroup} platform as it is configured. Set the configuration in the generated IDE project instead."); + return; + } + + SetIl2CppCompilerConfigurationInternal(targetGroup, configuration); + } + [StaticAccessor("GetPlayerSettings().GetEditorOnlyForUpdate()")] - public static extern void SetIl2CppCompilerConfiguration(BuildTargetGroup targetGroup, Il2CppCompilerConfiguration configuration); + [NativeMethod("SetIl2CppCompilerConfiguration")] + private static extern void SetIl2CppCompilerConfigurationInternal(BuildTargetGroup targetGroup, Il2CppCompilerConfiguration configuration); [StaticAccessor("GetPlayerSettings().GetEditorOnly()")] public static extern Il2CppCompilerConfiguration GetIl2CppCompilerConfiguration(BuildTargetGroup targetGroup); diff --git a/Editor/Mono/PlayerSettingsFacebook.bindings.cs b/Editor/Mono/PlayerSettingsFacebook.bindings.cs index 9e38c7b253..0a9c1190fa 100644 --- a/Editor/Mono/PlayerSettingsFacebook.bindings.cs +++ b/Editor/Mono/PlayerSettingsFacebook.bindings.cs @@ -12,70 +12,49 @@ namespace UnityEditor { public partial class PlayerSettings : UnityEngine.Object { - [NativeHeader("Runtime/Misc/PlayerSettings.h")] + [Obsolete("Facebook support was removed in 2019.3", true)] public partial class Facebook { - [NativeProperty("facebookSdkVersion")] - public extern static string sdkVersion + public static string sdkVersion { - [StaticAccessor("GetPlayerSettings().GetEditorOnly()", StaticAccessorType.Dot)] - get; - [StaticAccessor("GetPlayerSettings().GetEditorOnlyForUpdate()", StaticAccessorType.Dot)] - set; + get { throw new NotImplementedException("Facebook support was removed in 2019.3"); } + set { throw new NotImplementedException("Facebook support was removed in 2019.3"); } } - [NativeProperty("facebookAppId")] - public extern static string appId + public static string appId { - [StaticAccessor("GetPlayerSettings().GetEditorOnly()", StaticAccessorType.Dot)] - get; - [StaticAccessor("GetPlayerSettings().GetEditorOnlyForUpdate()", StaticAccessorType.Dot)] - set; + get { throw new NotImplementedException("Facebook support was removed in 2019.3"); } + set { throw new NotImplementedException("Facebook support was removed in 2019.3"); } } - [NativeProperty("facebookCookies", TargetType.Field)] - public extern static bool useCookies + public static bool useCookies { - [StaticAccessor("GetPlayerSettings().GetEditorOnly()", StaticAccessorType.Dot)] - get; - [StaticAccessor("GetPlayerSettings().GetEditorOnlyForUpdate()", StaticAccessorType.Dot)] - set; + get { throw new NotImplementedException("Facebook support was removed in 2019.3"); } + set { throw new NotImplementedException("Facebook support was removed in 2019.3"); } } - [NativeProperty("facebookLogging", TargetType.Field)] - internal extern static bool useLogging + internal static bool useLogging { - [StaticAccessor("GetPlayerSettings().GetEditorOnly()", StaticAccessorType.Dot)] - get; - [StaticAccessor("GetPlayerSettings().GetEditorOnlyForUpdate()", StaticAccessorType.Dot)] - set; + get { throw new NotImplementedException("Facebook support was removed in 2019.3"); } + set { throw new NotImplementedException("Facebook support was removed in 2019.3"); } } - [NativeProperty("facebookStatus", TargetType.Field)] - public extern static bool useStatus + public static bool useStatus { - [StaticAccessor("GetPlayerSettings().GetEditorOnly()", StaticAccessorType.Dot)] - get; - [StaticAccessor("GetPlayerSettings().GetEditorOnlyForUpdate()", StaticAccessorType.Dot)] - set; + get { throw new NotImplementedException("Facebook support was removed in 2019.3"); } + set { throw new NotImplementedException("Facebook support was removed in 2019.3"); } } - [NativeProperty("facebookXfbml", TargetType.Field)] - internal extern static bool useXfbml + internal static bool useXfbml { - [StaticAccessor("GetPlayerSettings().GetEditorOnly()", StaticAccessorType.Dot)] - get; - [StaticAccessor("GetPlayerSettings().GetEditorOnlyForUpdate()", StaticAccessorType.Dot)] - set; + get { throw new NotImplementedException("Facebook support was removed in 2019.3"); } + set { throw new NotImplementedException("Facebook support was removed in 2019.3"); } } - [NativeProperty("facebookFrictionlessRequests", TargetType.Field)] - public extern static bool useFrictionlessRequests + public static bool useFrictionlessRequests { - [StaticAccessor("GetPlayerSettings().GetEditorOnly()", StaticAccessorType.Dot)] - get; - [StaticAccessor("GetPlayerSettings().GetEditorOnlyForUpdate()", StaticAccessorType.Dot)] - set; + get { throw new NotImplementedException("Facebook support was removed in 2019.3"); } + set { throw new NotImplementedException("Facebook support was removed in 2019.3"); } } } } diff --git a/Editor/Mono/PlayerSettingsWSA.bindings.cs b/Editor/Mono/PlayerSettingsWSA.bindings.cs index 8fd84d86c5..3778f9c7f0 100644 --- a/Editor/Mono/PlayerSettingsWSA.bindings.cs +++ b/Editor/Mono/PlayerSettingsWSA.bindings.cs @@ -75,6 +75,7 @@ public enum WSACapability SystemManagement = 34, UserDataTasks = 35, UserNotificationListener = 36, + GazeInput = 37 } // match these with the capabilities listed in MetroCapabilities.h diff --git a/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesTreeView.cs b/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesTreeView.cs index c0ac3cdd71..da24ffbc5c 100644 --- a/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesTreeView.cs +++ b/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesTreeView.cs @@ -5,7 +5,6 @@ using System; using UnityEngine; using System.Collections.Generic; -using System.Linq; using UnityEditor.IMGUI.Controls; using UnityEditor.SceneManagement; using Object = UnityEngine.Object; @@ -115,20 +114,6 @@ public void SetApplyTarget(GameObject prefabInstanceRoot, GameObject prefabAsset EnableAllItems(true); } - static string NicifyPropertyName(string propertyPath) - { - var result = ObjectNames.NicifyVariableName(propertyPath); - result = result.Replace("Local ", ""); - return result; - } - - static string GetModificationValueString(PropertyModification mod) - { - if (mod.objectReference != null) - return mod.objectReference.name; - return mod.value; - } - void BuildPrefabOverridesPerObject(out Dictionary instanceIDToPrefabOverridesMap) { instanceIDToPrefabOverridesMap = new Dictionary(); @@ -370,39 +355,6 @@ static void UpdateChildrenIncludedState(PrefabOverridesTreeViewItem item, bool v } } - static void UpdateParentsIncludedState(PrefabOverridesTreeViewItem item) - { - if (item.depth > 0) - { - var parent = item.parent as PrefabOverridesTreeViewItem; - bool hasIncludedChildren = false; - bool hasExcludedChildren = false; - foreach (var child in parent.children) - { - var included = (child as PrefabOverridesTreeViewItem).included; - hasIncludedChildren |= included != ToggleValue.FALSE; - hasExcludedChildren |= included != ToggleValue.TRUE; - if (hasIncludedChildren && hasExcludedChildren) - { - break; - } - } - if (hasIncludedChildren && hasExcludedChildren) - { - parent.included = ToggleValue.MIXED; - } - else if (hasIncludedChildren) - { - parent.included = ToggleValue.TRUE; - } - else - { - parent.included = ToggleValue.FALSE; - } - UpdateParentsIncludedState(parent); - } - } - protected override void RowGUI(RowGUIArgs args) { baseIndent = 4f; @@ -502,29 +454,6 @@ struct ChangedModification public string propertyPath { get; set; } } - enum Operation { APPLY, REVERT } - - static void GetSelectedModificationsRecursive(TreeViewItem treeViewItem, List selectedModifications) - { - var objectItem = treeViewItem as PrefabOverridesTreeViewItem; - if (objectItem == null) - return; - - if (objectItem.included == ToggleValue.FALSE) - return; - - if (objectItem.singleModification != null) - { - selectedModifications.Add(objectItem.singleModification); - } - - if (objectItem.hasChildren) - { - foreach (var child in objectItem.children) - GetSelectedModificationsRecursive(child, selectedModifications); - } - } - class IdSequence { public int get() { return m_NextId++; } diff --git a/Editor/Mono/Prefabs/PrefabUtility.cs b/Editor/Mono/Prefabs/PrefabUtility.cs index 25fa4f6bb1..ee56f048f4 100644 --- a/Editor/Mono/Prefabs/PrefabUtility.cs +++ b/Editor/Mono/Prefabs/PrefabUtility.cs @@ -8,14 +8,12 @@ using System.Linq; using UnityEngine; using UnityEngine.Assertions; -using UnityEditor; using UnityEditor.Utils; using UnityEngine.SceneManagement; using UnityEditor.SceneManagement; using Object = UnityEngine.Object; using RequiredByNativeCodeAttribute = UnityEngine.Scripting.RequiredByNativeCodeAttribute; using UnityEditor.VersionControl; -using UnityEditorInternal; namespace UnityEditor { @@ -1217,6 +1215,9 @@ private static void ValidatePath(GameObject instanceRoot, string path) if (!Paths.IsValidAssetPath(path, ".prefab")) throw new ArgumentException("Given path is not valid: '" + path + "'"); + if (Directory.Exists(path)) + throw new ArgumentException("Overwriting a folder with an Asset is not allowed: '" + path + "'"); + string directory = Path.GetDirectoryName(path); bool isRootFolder = false; @@ -1262,12 +1263,6 @@ private static void ReplacePrefabArgumentCheck(GameObject root, string path) ValidatePath(root, path); } - private static bool IsPrefabInstanceRoot(GameObject gameObject) - { - var instanceRoot = GetOutermostPrefabInstanceRoot(gameObject); - return instanceRoot != null && instanceRoot == gameObject; - } - public static GameObject SaveAsPrefabAsset(GameObject instanceRoot, string assetPath, out bool success) { SaveAsPrefabAssetArgumentCheck(instanceRoot, assetPath); diff --git a/Editor/Mono/PreferencesWindow/PreferencesSettingsProviders.cs b/Editor/Mono/PreferencesWindow/PreferencesSettingsProviders.cs index cd6b5dc34a..4520b5819b 100644 --- a/Editor/Mono/PreferencesWindow/PreferencesSettingsProviders.cs +++ b/Editor/Mono/PreferencesWindow/PreferencesSettingsProviders.cs @@ -13,7 +13,6 @@ using UnityEditor.Connect; using UnityEngine.UIElements; using UnityEditor.Experimental; -using UnityEditor.StyleSheets; using UnityEngine.TestTools; using UnityEditor.Collaboration; @@ -68,6 +67,7 @@ internal class GeneralProperties internal class ExternalProperties { + public static readonly GUIContent addUnityProjeToSln = EditorGUIUtility.TrTextContent("Add .unityproj's to .sln"); public static readonly GUIContent editorAttaching = EditorGUIUtility.TrTextContent("Editor Attaching"); public static readonly GUIContent changingThisSettingRequiresRestart = EditorGUIUtility.TrTextContent("Changing this setting requires a restart to take effect."); public static readonly GUIContent revisionControlDiffMerge = EditorGUIUtility.TrTextContent("Revision Control Diff/Merge"); @@ -173,6 +173,14 @@ 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. " + + "\n(This does work with Visual Studio Pro)" + ); + private const int kRecentAppsCount = 10; SortedDictionary>> s_CachedColors = null; @@ -335,7 +343,23 @@ private void ShowExternalApplications(string searchContext) // Applications FilePopup(ExternalProperties.externalScriptEditor, m_ScriptEditorPath, ref m_ScriptAppDisplayNames, ref m_ScriptApps, m_ScriptEditorPath, "internal", OnScriptEditorChanged); - CodeEditor.Editor.Current.OnGUI(); + #pragma warning disable 618 + if (ScriptEditorUtility.GetScriptEditorFromPath(CodeEditor.CurrentEditorInstallation) == ScriptEditorUtility.ScriptEditor.Other) + { + 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(); bool oldValue = m_AllowAttachedDebuggingOfEditor; m_AllowAttachedDebuggingOfEditor = EditorGUILayout.Toggle(ExternalProperties.editorAttaching, m_AllowAttachedDebuggingOfEditor); @@ -346,6 +370,14 @@ private void ShowExternalApplications(string searchContext) if (m_AllowAttachedDebuggingOfEditorStateChangedThisSession) GUILayout.Label(ExternalProperties.changingThisSettingRequiresRestart, EditorStyles.helpBox); + if (GetSelectedScriptEditor() == ScriptEditorUtility.ScriptEditor.VisualStudioExpress) + { + GUILayout.BeginHorizontal(EditorStyles.helpBox); + GUILayout.Label("", Constants.warningIcon); + GUILayout.Label(k_ExpressNotSupportedMessage, Constants.errorLabel); + GUILayout.EndHorizontal(); + } + GUILayout.Space(10f); FilePopup(ExternalProperties.imageApplication, m_ImageAppPath, ref m_ImageAppDisplayNames, ref m_ImageApps, m_ImageAppPath, "internal", null); @@ -379,9 +411,38 @@ private void ShowExternalApplications(string searchContext) ApplyChangesToPrefs(); } + private void DoUnityProjCheckbox() + { + bool isConfigurable = false; + bool value = false; + + ScriptEditorUtility.ScriptEditor scriptEditor = GetSelectedScriptEditor(); + + if (scriptEditor == ScriptEditorUtility.ScriptEditor.MonoDevelop) + { + isConfigurable = true; + value = m_ExternalEditorSupportsUnityProj; + } + + using (new EditorGUI.DisabledScope(!isConfigurable)) + { + value = EditorGUILayout.Toggle(ExternalProperties.addUnityProjeToSln, value); + } + + if (isConfigurable) + m_ExternalEditorSupportsUnityProj = value; + } + + #pragma warning disable 618 + private ScriptEditorUtility.ScriptEditor GetSelectedScriptEditor() + { + return ScriptEditorUtility.GetScriptEditorFromPath(m_ScriptEditorPath.str); + } + private void OnScriptEditorChanged() { CodeEditor.SetExternalScriptEditor(m_ScriptEditorPath); + UnityEditor.VisualStudioIntegration.UnityVSSupport.ScriptEditorChanged(m_ScriptEditorPath.str); } private void ShowUnityConnectPrefs(string searchContext) @@ -888,17 +949,6 @@ private void WritePreferences() UnityEditor.Lightmapping.UpdateCachePath(); } - static private void SetupDefaultPreferences() - { - } - - static private string GetProgramFilesFolder() - { - string result = Environment.GetEnvironmentVariable("ProgramFiles(x86)"); - if (result != null) return result; - return Environment.GetEnvironmentVariable("ProgramFiles"); - } - private int CurrentEditorScalingValue { get {return Mathf.RoundToInt(GUIUtility.pixelsPerPoint * 100); } @@ -906,7 +956,7 @@ private int CurrentEditorScalingValue private void ReadPreferences() { - m_ScriptEditorPath.str = CodeEditor.Editor.EditorInstallation.Path; + m_ScriptEditorPath.str = ScriptEditorUtility.GetExternalScriptEditor(); m_ExternalEditorSupportsUnityProj = EditorPrefs.GetBool("kExternalEditorSupportsUnityProj", false); m_ImageAppPath.str = EditorPrefs.GetString("kImagesDefaultApp"); @@ -914,7 +964,30 @@ private void ReadPreferences() m_ScriptApps = BuildAppPathList(m_ScriptEditorPath, kRecentScriptAppsKey, "internal"); m_ScriptAppsEditions = new string[m_ScriptApps.Length]; + if (Application.platform == RuntimePlatform.WindowsEditor) + { + foreach (var vsPaths in SyncVS.InstalledVisualStudios.Values) + foreach (var vsPath in vsPaths) + { + int index = Array.IndexOf(m_ScriptApps, vsPath.Path); + if (index == -1) + { + ArrayUtility.Add(ref m_ScriptApps, vsPath.Path); + ArrayUtility.Add(ref m_ScriptAppsEditions, vsPath.Edition); + } + else + { + m_ScriptAppsEditions[index] = vsPath.Edition; + } + } + } + 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) { diff --git a/Editor/Mono/PresetLibraries/PresetLibraryEditor.cs b/Editor/Mono/PresetLibraries/PresetLibraryEditor.cs index 1d74e0f872..53fc563615 100644 --- a/Editor/Mono/PresetLibraries/PresetLibraryEditor.cs +++ b/Editor/Mono/PresetLibraries/PresetLibraryEditor.cs @@ -6,7 +6,6 @@ using UnityEditor.VersionControl; using UnityEngine; using UnityEditorInternal; -using System.Collections.Generic; namespace UnityEditor { @@ -170,12 +169,6 @@ void Repaint() HandleUtility.Repaint(); } - void ValidateNoExtension(string value) - { - if (Path.HasExtension(value)) - Debug.LogError("currentLibraryWithoutExtension should not have an extension: " + value); - } - public string currentLibraryWithoutExtension { get @@ -237,18 +230,6 @@ string CreateNewLibraryCallback(string libraryName, PresetFileLocation fileLocat return PresetLibraryManager.instance.GetLastError(); } - static bool IsItemVisible(float scrollHeight, float itemYMin, float itemYMax, float scrollPos) - { - float yMin = itemYMin - scrollPos; - float yMax = itemYMax - scrollPos; - if (yMax < 0f) - return false; - if (yMin > scrollHeight) - return false; - - return true; - } - void OnLayoutChanged() { T lib = GetCurrentLib(); diff --git a/Editor/Mono/Preview/PreviewEditorWindow.cs b/Editor/Mono/Preview/PreviewEditorWindow.cs new file mode 100644 index 0000000000..aed0f776ea --- /dev/null +++ b/Editor/Mono/Preview/PreviewEditorWindow.cs @@ -0,0 +1,324 @@ +// 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 UnityEditor.Modules; +using UnityEditorInternal; +using UnityEngine; +using UnityEngine.Experimental.Rendering; +using UnityEngine.Scripting; + +namespace UnityEditor +{ + [Serializable] + internal abstract class PreviewEditorWindow : EditorWindow + { + static List s_PreviewWindows = new List(); + static PreviewEditorWindow s_LastFocused; + static PreviewEditorWindow s_RenderingPreview; + + [SerializeField] string m_PreviewName; + [SerializeField] bool m_ShowGizmos; + [SerializeField] int m_TargetDisplay; + [SerializeField] Color m_ClearColor; + [SerializeField] Vector2 m_TargetSize; + [SerializeField] FilterMode m_TextureFilterMode = FilterMode.Point; + [SerializeField] HideFlags m_TextureHideFlags = HideFlags.HideAndDontSave; + [SerializeField] bool m_RenderIMGUI; + [SerializeField] bool m_MaximizeOnPlay; + + private List m_AvailableWindowTypes; + + protected string previewName + { + get { return m_PreviewName; } + set { m_PreviewName = value; } + } + + protected bool showGizmos + { + get { return m_ShowGizmos; } + set + { + m_ShowGizmos = value; + } + } + + protected int targetDisplay + { + get { return m_TargetDisplay; } + set { m_TargetDisplay = value; } + } + + protected Color clearColor + { + get { return m_ClearColor; } + set { m_ClearColor = value; } + } + + protected Vector2 targetSize + { + get { return m_TargetSize; } + set { m_TargetSize = value; } + } + + protected FilterMode textureFilterMode + { + get { return m_TextureFilterMode; } + set { m_TextureFilterMode = value; } + } + + protected HideFlags textureHideFlags + { + get { return m_TextureHideFlags; } + set { m_TextureHideFlags = value; } + } + + protected bool renderIMGUI + { + get { return m_RenderIMGUI; } + set { m_RenderIMGUI = value; } + } + + public bool maximizeOnPlay + { + get { return m_MaximizeOnPlay; } + set { m_MaximizeOnPlay = value; } + } + + RenderTexture m_TargetTexture; + ColorSpace m_CurrentColorSpace = ColorSpace.Uninitialized; + + class RenderingPreview : IDisposable + { + bool disposed = false; + + public RenderingPreview(PreviewEditorWindow previewWindow) + { + PreviewEditorWindow.s_RenderingPreview = previewWindow; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + // Protected implementation of Dispose pattern. + protected virtual void Dispose(bool disposing) + { + if (disposed) + return; + + if (disposing) + { + PreviewEditorWindow.s_RenderingPreview = null; + } + + disposed = true; + } + } + + protected PreviewEditorWindow() + { + RegisterWindow(); + } + + protected RenderTexture RenderPreview(Vector2 mousePosition, bool clearTexture) + { + using (var renderingPreview = new RenderingPreview(this)) + { + var currentTargetDisplay = 0; + if (ModuleManager.ShouldShowMultiDisplayOption()) + { + // Display Targets can have valid targets from 0 to 7. + System.Diagnostics.Debug.Assert(targetDisplay < 8, "Display Target is Out of Range"); + currentTargetDisplay = targetDisplay; + } + + ConfigureTargetTexture((int)targetSize.x, (int)targetSize.y, clearTexture, previewName); + + if (Event.current == null || Event.current.type != EventType.Repaint) + return m_TargetTexture; + + Vector2 oldOffset = GUIUtility.s_EditorScreenPointOffset; + GUIUtility.s_EditorScreenPointOffset = Vector2.zero; + SavedGUIState oldState = SavedGUIState.Create(); + + EditorGUIUtility.RenderPreviewCamerasInternal(m_TargetTexture, currentTargetDisplay, mousePosition, showGizmos, renderIMGUI); + + oldState.ApplyAndForget(); + GUIUtility.s_EditorScreenPointOffset = oldOffset; + + return m_TargetTexture; + } + } + + protected List GetAvailableWindowTypes() + { + return m_AvailableWindowTypes ?? (m_AvailableWindowTypes = TypeCache.GetTypesDerivedFrom(typeof(PreviewEditorWindow)).OrderBy(type => type.Name).ToList()); + } + + protected void SwapMainWindow(Type type) + { + if (type.BaseType != typeof(PreviewEditorWindow)) + throw new ArgumentException("Type should derive from " + typeof(PreviewEditorWindow).Name); + + if (type.Name != GetType().Name) + { + var window = CreateInstance(type) as PreviewEditorWindow; + window.autoRepaintOnSceneChange = true; + var da = m_Parent as DockArea; + if (da) + { + da.AddTab(window); + da.RemoveTab(this); + DestroyImmediate(this, true); + } + } + } + + private void ClearTargetTexture() + { + if (m_TargetTexture.IsCreated()) + { + var previousTarget = RenderTexture.active; + RenderTexture.active = m_TargetTexture; + GL.Clear(true, true, clearColor); + RenderTexture.active = previousTarget; + } + } + + private void ConfigureTargetTexture(int width, int height, bool clearTexture, string name) + { + // Changing color space requires destroying the entire RT object and recreating it + if (m_TargetTexture && m_CurrentColorSpace != QualitySettings.activeColorSpace) + { + UnityEngine.Object.DestroyImmediate(m_TargetTexture); + } + if (!m_TargetTexture) + { + m_CurrentColorSpace = QualitySettings.activeColorSpace; + m_TargetTexture = new RenderTexture(0, 0, 24, SystemInfo.GetGraphicsFormat(DefaultFormat.LDR)); + m_TargetTexture.name = name + " RT"; + m_TargetTexture.filterMode = textureFilterMode; + m_TargetTexture.hideFlags = textureHideFlags; + } + + // Changes to these attributes require a release of the texture + if (m_TargetTexture.width != width || m_TargetTexture.height != height) + { + m_TargetTexture.Release(); + m_TargetTexture.width = width; + m_TargetTexture.height = height; + m_TargetTexture.antiAliasing = 1; + clearTexture = true; + } + + m_TargetTexture.Create(); + + if (clearTexture) + { + ClearTargetTexture(); + } + } + + internal static PreviewEditorWindow GetRenderingPreview() + { + return s_RenderingPreview; + } + + internal static PreviewEditorWindow GetMainPreviewWindow() + { + if (s_LastFocused == null && s_PreviewWindows != null) + { + RemoveDisabledWindows(); + if (s_PreviewWindows.Count > 0) + s_LastFocused = s_PreviewWindows[0]; + } + + return s_LastFocused; + } + + private static void RemoveDisabledWindows() + { + if (s_PreviewWindows == null) + return; + + s_PreviewWindows.RemoveAll(window => window == null); + } + + internal static Vector2 GetMainPreviewTargetSize() + { + var prevWindow = GetMainPreviewWindow(); + if (prevWindow) + return prevWindow.GetPreviewSize(); + return new Vector2(640f, 480f); + } + + internal Vector2 GetPreviewSize() + { + return targetSize; + } + + private void RegisterWindow() + { + RemoveDisabledWindows(); + if (!s_PreviewWindows.Contains(this)) + s_PreviewWindows.Add(this); + } + + public bool IsShowingGizmos() + { + return showGizmos; + } + + public void SetShowGizmos(bool value) + { + showGizmos = value; + Repaint(); + } + + protected void SetVSync(bool enable) + { + m_Parent.EnableVSync(enable); + } + + protected void SetFocus(bool focused) + { + if (!focused && s_LastFocused == this) + { + InternalEditorUtility.OnGameViewFocus(false); + } + else if (focused) + { + InternalEditorUtility.OnGameViewFocus(true); + s_LastFocused = this; + Repaint(); + } + } + + internal static bool IsPreviewWindowOpen() + { + return GetMainPreviewWindow() != null; + } + + internal static void RepaintAll() + { + if (s_PreviewWindows == null) + return; + + foreach (PreviewEditorWindow previewWindow in s_PreviewWindows) + previewWindow.Repaint(); + } + + [RequiredByNativeCode] + private static void GetMainPreviewTargetSizeNoBox(out Vector2 result) + { + result = GetMainPreviewTargetSize(); + } + } +} diff --git a/Editor/Mono/ProjectBrowser.cs b/Editor/Mono/ProjectBrowser.cs index 651638efde..c3439d35f9 100644 --- a/Editor/Mono/ProjectBrowser.cs +++ b/Editor/Mono/ProjectBrowser.cs @@ -15,7 +15,6 @@ using UnityEditorInternal; using UnityEngine.Scripting; using Object = UnityEngine.Object; -using UnityEditor.StyleSheets; namespace UnityEditor { @@ -303,15 +302,6 @@ void Awake() } } - string GetAnalyticsSizeLabel(float size) - { - if (size > 600) - return "Larger than 600 pix"; - if (size < 240) - return "Less than 240 pix"; - return "240 - 600 pix"; - } - static internal ItemType GetItemType(int instanceID) { if (SavedSearchFilters.IsSavedFilter(instanceID)) @@ -933,31 +923,6 @@ void SyncFilterGUI() m_SearchFieldText = m_SearchFilter.FilterToSearchFieldString(); } - static int GetParentInstanceID(int objectInstanceID) - { - string propertyPath = AssetDatabase.GetAssetPath(objectInstanceID); - int pos = propertyPath.LastIndexOf("/"); - if (pos >= 0) - { - string folderPath = propertyPath.Substring(0, pos); - Object obj = AssetDatabase.LoadAssetAtPath(folderPath, typeof(Object)); - if (obj != null) - return obj.GetInstanceID(); - } - else - { - Debug.LogError("Invalid path: " + propertyPath); - } - return -1; - } - - bool IsShowingFolder(int folderInstanceID) - { - string folderPath = AssetDatabase.GetAssetPath(folderInstanceID); - bool contains = new List(m_SearchFilter.folders).Contains(folderPath); - return contains; - } - void ShowFolderContents(int folderInstanceID, bool revealAndFrameInFolderTree) { if (m_ViewMode != ViewMode.TwoColumns) @@ -1139,6 +1104,7 @@ static void OpenSelectedFolders() } } + // Called from EditorHelper static void OpenSelectedFoldersInInternalExplorer() { if (!IsFolderTreeViewContextClick()) @@ -2944,12 +2910,14 @@ internal void ShowObjectsInList(int[] instanceIDs) } } + // Called from AssetsMenu static void ShowSelectedObjectsInLastInteractedProjectBrowser() { // Only one ProjectBrowser can have focus at a time so if we find one just return that one if (s_LastInteractedProjectBrowser != null) { int[] instanceIDs = Selection.instanceIDs; + s_LastInteractedProjectBrowser.ShowObjectsInList(instanceIDs); } } diff --git a/Editor/Mono/ProjectWindow/ProjectWindowUtil.cs b/Editor/Mono/ProjectWindow/ProjectWindowUtil.cs index 7ee998c766..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; diff --git a/Editor/Mono/RemoteInput/Remoting.bindings.cs b/Editor/Mono/RemoteInput/Remoting.bindings.cs new file mode 100644 index 0000000000..8e5bc95d56 --- /dev/null +++ b/Editor/Mono/RemoteInput/Remoting.bindings.cs @@ -0,0 +1,22 @@ +// 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; +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; + +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Unity.Remoting.Editor")] + +namespace UnityEditor.Remoting +{ + [NativeHeader("Editor/Mono/RemoteInput/Remoting.bindings.h")] + internal partial class RemotingInternal + { + extern static private void ReceiveData(IntPtr buffer, int bufferSize); + + extern static public void SetConnectedExternally(bool connected); + static public unsafe void ReceiveData(NativeArray buffer, int bufferSize) { ReceiveData((IntPtr)buffer.GetUnsafeReadOnlyPtr(), bufferSize); } + } +} diff --git a/Editor/Mono/RetainedMode.cs b/Editor/Mono/RetainedMode.cs index 0e0d2420b4..5056f22c59 100644 --- a/Editor/Mono/RetainedMode.cs +++ b/Editor/Mono/RetainedMode.cs @@ -35,7 +35,7 @@ static RetainedMode() UIElementsUtility.s_EndContainerCallback = OnEndContainer; Panel.loadResourceFunc = StyleSheetResourceUtil.LoadResource; - StyleSheetApplicator.getCursorIdFunc = UIElementsEditorUtility.GetCursorId; + StylePropertyReader.getCursorIdFunc = UIElementsEditorUtility.GetCursorId; Panel.TimeSinceStartup = () => (long)(EditorApplication.timeSinceStartup * 1000.0f); } diff --git a/Editor/Mono/SceneHierarchy.cs b/Editor/Mono/SceneHierarchy.cs index a26a71b786..e1afacca4d 100644 --- a/Editor/Mono/SceneHierarchy.cs +++ b/Editor/Mono/SceneHierarchy.cs @@ -279,13 +279,6 @@ bool AreCustomScenesValid(Scene[] customScenes) return true; } - bool IsShowingPreviewScene() - { - if (m_CustomScenes != null && m_CustomScenes.Length > 0) - return EditorSceneManager.IsPreviewScene(m_CustomScenes[0]); - return false; - } - void SetUpSortMethodLists() { m_SortingObjects = new Dictionary(); @@ -936,6 +929,13 @@ void ExecuteCommands() evt.Use(); GUIUtility.ExitGUI(); } + else if (evt.commandName == EventCommandNames.Rename) + { + if (execute) + RenameGO(); + evt.Use(); + GUIUtility.ExitGUI(); + } else if (evt.commandName == EventCommandNames.Copy) { if (execute) @@ -1247,20 +1247,6 @@ List GetSelectedScenes() return selectedSceneHandles; } - List GetSelectedGameObjects() - { - var selectedGameObjects = new List(); - int[] instanceIDs = m_TreeView.GetSelection(); - foreach (int id in instanceIDs) - { - if (!IsSceneHeaderInHierarchyWindow(EditorSceneManager.GetSceneByHandle(id))) - { - selectedGameObjects.Add(id); - } - } - return selectedGameObjects; - } - Scene GetLastSceneInHierarchy() { return dataSource.GetLastScene(); diff --git a/Editor/Mono/SceneManagement/EditorSceneManager.cs b/Editor/Mono/SceneManagement/EditorSceneManager.cs index ac252a202f..fa774cfe02 100644 --- a/Editor/Mono/SceneManagement/EditorSceneManager.cs +++ b/Editor/Mono/SceneManagement/EditorSceneManager.cs @@ -21,6 +21,7 @@ public sealed partial class EditorSceneManager public delegate void SceneClosedCallback(Scene scene); public delegate void SceneSavingCallback(Scene scene, string path); public delegate void SceneSavedCallback(Scene scene); + public delegate void SceneDirtiedCallback(Scene scene); public static event NewSceneCreatedCallback newSceneCreated; public static event SceneOpeningCallback sceneOpening; @@ -29,6 +30,7 @@ public sealed partial class EditorSceneManager public static event SceneClosedCallback sceneClosed; public static event SceneSavingCallback sceneSaving; public static event SceneSavedCallback sceneSaved; + public static event SceneDirtiedCallback sceneDirtied; [RequiredByNativeCode] private static void Internal_NewSceneCreated(Scene scene, NewSceneSetup setup, NewSceneMode mode) @@ -79,6 +81,13 @@ private static void Internal_SceneSaved(Scene scene) sceneSaved(scene); } + [RequiredByNativeCode] + private static void Internal_SceneDirtied(Scene scene) + { + if (sceneDirtied != null) + sceneDirtied(scene); + } + [RequiredByNativeCode] private static Transform Internal_GetParentTransformForNewGameObjects() { diff --git a/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStage.cs b/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStage.cs index 33258aee8b..08a62ef1e3 100644 --- a/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStage.cs +++ b/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStage.cs @@ -23,6 +23,7 @@ public class PrefabStage { public static event Action prefabStageOpened; public static event Action prefabStageClosing; + public static event Action prefabStageDirtied; public static event Action prefabSaving; public static event Action prefabSaved; internal static event Action prefabIconChanged; @@ -36,6 +37,7 @@ public class PrefabStage int m_LastSceneDirtyID; bool m_IgnoreNextAssetImportedEventForCurrentPrefab; bool m_PrefabWasChangedOnDisk; + bool m_StageDirtiedFired; HideFlagUtility m_HideFlagUtility; Texture2D m_PrefabFileIcon; bool m_TemporarilyDisableAutoSave; @@ -156,6 +158,7 @@ internal bool LoadStage(string prefabPath) m_PrefabFileIcon = DeterminePrefabFileIconFromInstanceRootGameObject(); m_LastRootTransform = m_PrefabContentsRoot.transform; m_InitialSceneDirtyID = m_PreviewScene.dirtyID; + m_StageDirtiedFired = false; UpdateEnvironmentHideFlags(); } else @@ -206,6 +209,7 @@ void Cleanup() m_HideFlagUtility = null; m_PrefabAssetPath = null; m_InitialSceneDirtyID = 0; + m_StageDirtiedFired = false; m_LastSceneDirtyID = 0; m_IgnoreNextAssetImportedEventForCurrentPrefab = false; m_PrefabWasChangedOnDisk = false; @@ -241,8 +245,17 @@ internal void Update() return; if (HasSceneBeenModified()) + { m_AnalyticsDidUserModify = true; + if (!m_StageDirtiedFired) + { + m_StageDirtiedFired = true; + if (prefabStageDirtied != null) + prefabStageDirtied(this); + } + } + UpdateEnvironmentHideFlagsIfNeeded(); HandleAutoSave(); HandlePrefabChangedOnDisk(); @@ -351,6 +364,7 @@ public void ClearDirtiness() { EditorSceneManager.ClearSceneDirtiness(m_PreviewScene); m_InitialSceneDirtyID = m_PreviewScene.dirtyID; + m_StageDirtiedFired = false; } bool PromptIfMissingBasePrefabForVariant() @@ -701,13 +715,6 @@ internal void OnAssetsChangedOnHDD(string[] importedAssets, string[] deletedAsse } } - void DestroyPrefabInstance() - { - if (m_PrefabContentsRoot == null) - return; - UnityEngine.Object.DestroyImmediate(m_PrefabContentsRoot); - } - internal bool HasSceneBeenModified() { return m_PreviewScene.dirtyID != m_InitialSceneDirtyID; diff --git a/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStageUtility.cs b/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStageUtility.cs index e3afdfbb2f..5c9792bb8c 100644 --- a/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStageUtility.cs +++ b/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStageUtility.cs @@ -7,12 +7,10 @@ using UnityEditor.SceneManagement; using UnityEditor.ShortcutManagement; using UnityEngine; -using UnityEngine.Assertions; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using UnityEngine.Scripting; using System.Linq; -using System.Collections.Generic; namespace UnityEditor.Experimental.SceneManagement { @@ -442,27 +440,5 @@ static Canvas GetCanvasInScene(GameObject instanceRoot) } return null; } - - static GameObject CreateLight(Color color, float intensity, Quaternion orientation) - { - GameObject lightGO = EditorUtility.CreateGameObjectWithHideFlags("Directional Light", HideFlags.HideAndDontSave, typeof(Light)); - lightGO.transform.rotation = orientation; - var light = lightGO.GetComponent(); - light.type = LightType.Directional; - light.intensity = intensity; - light.color = color; - light.enabled = true; - light.shadows = LightShadows.Soft; - return lightGO; - } - - static void CreateDefaultLights(Scene scene) - { - var light = CreateLight(new Color(0.769f, 0.769f, 0.769f, 1), 0.7f, Quaternion.Euler(40f, 40f, 0)); - var light2 = CreateLight(new Color(.4f, .4f, .45f, 0f) * .7f, 0.7f, Quaternion.Euler(340, 218, 177)); - - SceneManager.MoveGameObjectToScene(light, scene); - SceneManager.MoveGameObjectToScene(light2, scene); - } } } diff --git a/Editor/Mono/SceneModeWindows/LightingExplorerWindow.cs b/Editor/Mono/SceneModeWindows/LightingExplorerWindow.cs index 3b335ade14..2e53d0379a 100644 --- a/Editor/Mono/SceneModeWindows/LightingExplorerWindow.cs +++ b/Editor/Mono/SceneModeWindows/LightingExplorerWindow.cs @@ -4,21 +4,20 @@ using UnityEngine; using UnityEngine.Rendering; -using System.Collections.Generic; +using UnityEditor.Rendering; using System.Linq; using System; namespace UnityEditor { - [System.AttributeUsage(System.AttributeTargets.Class)] - public class LightingExplorerExtensionAttribute : System.Attribute + //Attribute that should be deprecated in 2020.1 + //Will be replaced by ScriptableRenderPipelineAttribute + //Kept for package compatibility and user SRP compatibility at the moment + [AttributeUsage(AttributeTargets.Class)] + public class LightingExplorerExtensionAttribute : ScriptableRenderPipelineExtensionAttribute { - internal System.Type renderPipelineType; - - public LightingExplorerExtensionAttribute(System.Type renderPipeline) - { - renderPipelineType = renderPipeline; - } + public LightingExplorerExtensionAttribute(Type renderPipeline) + : base(renderPipeline) {} } public interface ILightingExplorerExtension @@ -35,7 +34,6 @@ internal class LightingExplorerWindow : EditorWindow LightingExplorerTab[] m_TableTabs; GUIContent[] m_TabTitles; - float m_ToolbarPadding = -1; int m_SelectedTab = 0; System.Type m_CurrentSRPType = null; @@ -50,19 +48,6 @@ static void CreateLightingExplorerWindow() window.Show(); } - private float toolbarPadding - { - get - { - if (m_ToolbarPadding == -1) - { - var iconsSize = EditorStyles.iconButton.CalcSize(EditorGUI.GUIContents.helpIcon); - m_ToolbarPadding = (iconsSize.x * 2) + (EditorGUI.kControlVerticalSpacing * 3); - } - return m_ToolbarPadding; - } - } - void OnEnable() { titleContent = GetLocalizedTitleContent(); @@ -219,16 +204,11 @@ private ILightingExplorerExtension GetLightExplorerExtension(System.Type current if (currentSRPType == null) return GetDefaultLightingExplorerExtension(); - var extensionTypes = TypeCache.GetTypesDerivedFrom(); - - foreach (System.Type extensionType in extensionTypes) + Type extensionType = RenderPipelineEditorUtility.FetchFirstCompatibleTypeUsingScriptableRenderPipelineExtension(); + if (extensionType != null) { - LightingExplorerExtensionAttribute attribute = System.Attribute.GetCustomAttribute(extensionType, typeof(LightingExplorerExtensionAttribute)) as LightingExplorerExtensionAttribute; - if (attribute != null && attribute.renderPipelineType == currentSRPType) - { - ILightingExplorerExtension extension = (ILightingExplorerExtension)System.Activator.CreateInstance(extensionType); - return extension; - } + ILightingExplorerExtension extension = (ILightingExplorerExtension)System.Activator.CreateInstance(extensionType); + return extension; } // no light explorer extension found for current srp, return the default one diff --git a/Editor/Mono/SceneModeWindows/LightingWindow.cs b/Editor/Mono/SceneModeWindows/LightingWindow.cs index 9f0fc44913..5d2475efa6 100644 --- a/Editor/Mono/SceneModeWindows/LightingWindow.cs +++ b/Editor/Mono/SceneModeWindows/LightingWindow.cs @@ -99,7 +99,7 @@ void OnSelectionChange() static internal void RepaintSceneAndGameViews() { SceneView.RepaintAll(); - GameView.RepaintAll(); + PreviewEditorWindow.RepaintAll(); } void OnGUI() diff --git a/Editor/Mono/SceneModeWindows/LightingWindowBakeSettings.cs b/Editor/Mono/SceneModeWindows/LightingWindowBakeSettings.cs index cd66d6407b..baec1cdd39 100644 --- a/Editor/Mono/SceneModeWindows/LightingWindowBakeSettings.cs +++ b/Editor/Mono/SceneModeWindows/LightingWindowBakeSettings.cs @@ -3,12 +3,8 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; -using System.Collections.Generic; -using System.Collections; using System.Linq; -using UnityEditor.AnimatedValues; using UnityEngine.Rendering; -using UnityEditorInternal; using UnityEngine; using UnityEngineInternal; using Object = UnityEngine.Object; @@ -70,6 +66,7 @@ internal class LightingWindowBakeSettings SerializedProperty m_PVRFilteringAtrousPositionSigmaAO; SerializedProperty m_PVREnvironmentMIS; SerializedProperty m_PVREnvironmentSampleCount; + SerializedProperty m_LightProbeSampleCountMultiplier; SerializedProperty m_BounceScale; SerializedProperty m_ExportTrainingData; @@ -135,6 +132,7 @@ private void InitSettings() m_PVRFilteringAtrousPositionSigmaAO = so.FindProperty("m_LightmapEditorSettings.m_PVRFilteringAtrousPositionSigmaAO"); m_PVREnvironmentMIS = so.FindProperty("m_LightmapEditorSettings.m_PVREnvironmentMIS"); m_PVREnvironmentSampleCount = so.FindProperty("m_LightmapEditorSettings.m_PVREnvironmentSampleCount"); + m_LightProbeSampleCountMultiplier = so.FindProperty("m_LightmapEditorSettings.m_LightProbeSampleCountMultiplier"); //dev debug properties m_BounceScale = so.FindProperty("m_GISettings.m_BounceScale"); @@ -158,8 +156,6 @@ public void OnDisable() m_RenderSettingsSO.Dispose(); } - void Repaint() { InspectorWindow.RepaintAllInspectors(); } - static void DrawResolutionField(SerializedProperty resolution, GUIContent label) { GUILayout.BeginHorizontal(); @@ -353,7 +349,7 @@ public void DeveloperBuildSettingsGUI() Lightmapping.enlightenForceUpdates = EditorGUILayout.Toggle(Styles.ForceUpdates, Lightmapping.enlightenForceUpdates); Lightmapping.enlightenForceWhiteAlbedo = EditorGUILayout.Toggle(Styles.ForceWhiteAlbedo, Lightmapping.enlightenForceWhiteAlbedo); - if (LightmapEditorSettings.lightmapper == LightmapEditorSettings.Lightmapper.ProgressiveCPU) + if (m_BakeBackend.intValue == (int)LightmapEditorSettings.Lightmapper.ProgressiveCPU) { EditorGUILayout.PropertyField(m_ExportTrainingData, Styles.ExportTrainingData); @@ -389,7 +385,7 @@ public void DeveloperBuildSettingsGUI() private void ClampFilterType(SerializedProperty filter) { - if (LightmapEditorSettings.lightmapper == LightmapEditorSettings.Lightmapper.ProgressiveGPU) + if (m_BakeBackend.intValue == (int)LightmapEditorSettings.Lightmapper.ProgressiveGPU) { // Force unsupported A-Trous filter back to Gaussian. if (filter.intValue == (int)LightmapEditorSettings.FilterType.ATrous) @@ -420,8 +416,6 @@ public enum DenoiserTarget } void DrawDenoiserTypeDropdown(SerializedProperty prop, GUIContent label, DenoiserTarget target) { - bool optixDenoiserSupported = LightmapEditorSettings.IsOptixDenoiserSupported(); - bool openImageDenoiserSupported = LightmapEditorSettings.IsOpenImageDenoiserSupported(); var rect = EditorGUILayout.GetControlRect(); EditorGUI.BeginProperty(rect, label, prop); rect = EditorGUI.PrefixLabel(rect, label); @@ -430,18 +424,24 @@ void DrawDenoiserTypeDropdown(SerializedProperty prop, GUIContent label, Denoise if (EditorGUI.DropdownButton(rect, Styles.DenoiserTypeStrings[index], FocusType.Passive)) { + bool radeonDenoiserSupported = LightmapEditorSettings.IsRadeonDenoiserSupported(); + bool openImageDenoiserSupported = LightmapEditorSettings.IsOpenImageDenoiserSupported(); + bool optixDenoiserSupported = LightmapEditorSettings.IsOptixDenoiserSupported(); var menu = new GenericMenu(); for (int i = 0; i < Styles.DenoiserTypeValues.Length; i++) { int value = Styles.DenoiserTypeValues[i]; bool optixDenoiserItem = (value == (int)LightmapEditorSettings.DenoiserType.Optix); bool openImageDenoiserItem = (value == (int)LightmapEditorSettings.DenoiserType.OpenImage); + bool radeonDenoiserItem = (value == (int)LightmapEditorSettings.DenoiserType.RadeonPro); bool selected = (value == prop.intValue); if (!optixDenoiserSupported && optixDenoiserItem) menu.AddDisabledItem(Styles.DenoiserTypeStrings[i], selected); else if (!openImageDenoiserSupported && openImageDenoiserItem) menu.AddDisabledItem(Styles.DenoiserTypeStrings[i], selected); + else if (!radeonDenoiserSupported && radeonDenoiserItem) + menu.AddDisabledItem(Styles.DenoiserTypeStrings[i], selected); else { if (target == DenoiserTarget.Direct) @@ -463,13 +463,59 @@ bool DenoiserSupported(LightmapEditorSettings.DenoiserType denoiserType) return false; if (denoiserType == LightmapEditorSettings.DenoiserType.OpenImage && !LightmapEditorSettings.IsOpenImageDenoiserSupported()) return false; + if (denoiserType == LightmapEditorSettings.DenoiserType.RadeonPro && !LightmapEditorSettings.IsRadeonDenoiserSupported()) + return false; + return true; } + void OnBakeBackedSelected(object userData) + { + m_BakeBackend.intValue = (int)userData; + } + + void BakeBackendGUI() + { + var rect = EditorGUILayout.GetControlRect(); + EditorGUI.BeginProperty(rect, Styles.BakeBackend, m_BakeBackend); + EditorGUI.BeginChangeCheck(); + rect = EditorGUI.PrefixLabel(rect, Styles.BakeBackend); + + int index = Math.Max(0, Array.IndexOf(Styles.BakeBackendValues, m_BakeBackend.intValue)); + + if (EditorGUI.DropdownButton(rect, Styles.BakeBackendStrings[index], FocusType.Passive)) + { + var menu = new GenericMenu(); + + for (int i = 0; i < Styles.BakeBackendValues.Length; i++) + { + int value = Styles.BakeBackendValues[i]; + bool selected = (value == m_BakeBackend.intValue); + + if (!SupportedRenderingFeatures.IsLightmapperSupported(value)) + menu.AddDisabledItem(Styles.BakeBackendStrings[i], selected); + else + menu.AddItem(Styles.BakeBackendStrings[i], selected, OnBakeBackedSelected, value); + } + menu.DropDown(rect); + } + if (EditorGUI.EndChangeCheck()) + InspectorWindow.RepaintAllInspectors(); // We need to repaint other inspectors that might need to update based on the selected backend. + + EditorGUI.EndProperty(); + + if (!SupportedRenderingFeatures.IsLightmapperSupported(m_BakeBackend.intValue)) + { + string fallbackLightmapper = Styles.BakeBackendStrings[SupportedRenderingFeatures.FallbackLightmapper()].text; + EditorGUILayout.HelpBox(Styles.LightmapperNotSupportedWarning.text + fallbackLightmapper, MessageType.Warning); + } + } + void GeneralLightmapSettingsGUI() { bool bakedGISupported = SupportedRenderingFeatures.IsLightmapBakeTypeSupported(LightmapBakeType.Baked); bool realtimeGISupported = SupportedRenderingFeatures.IsLightmapBakeTypeSupported(LightmapBakeType.Realtime); + bool lightmapperSupported = SupportedRenderingFeatures.IsLightmapperSupported(m_BakeBackend.intValue); if (!bakedGISupported && !realtimeGISupported) return; @@ -485,157 +531,194 @@ void GeneralLightmapSettingsGUI() { using (new EditorGUI.DisabledScope(!m_EnabledBakedGI.boolValue)) { - EditorGUI.BeginChangeCheck(); - EditorGUILayout.PropertyField(m_BakeBackend, Styles.BakeBackend); - if (EditorGUI.EndChangeCheck()) - InspectorWindow.RepaintAllInspectors(); // We need to repaint other inspectors that might need to update based on the selected backend. + BakeBackendGUI(); - if (LightmapEditorSettings.lightmapper != LightmapEditorSettings.Lightmapper.Enlighten) + if (lightmapperSupported) { - EditorGUI.indentLevel++; - - EditorGUILayout.PropertyField(m_PVRCulling, Styles.PVRCulling); + if (m_BakeBackend.intValue == (int)LightmapEditorSettings.Lightmapper.Enlighten) + { + EditorGUI.indentLevel++; - bool enableMIS = (m_PVREnvironmentMIS.intValue & 1) != 0; - if (EditorGUILayout.Toggle(Styles.PVREnvironmentMIS, enableMIS)) - m_PVREnvironmentMIS.intValue |= 1; - else - m_PVREnvironmentMIS.intValue &= ~1; + EditorGUILayout.PropertyField(m_FinalGather, Styles.FinalGather); + if (m_FinalGather.boolValue) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_FinalGatherRayCount, Styles.FinalGatherRayCount); + EditorGUILayout.PropertyField(m_FinalGatherFiltering, Styles.FinalGatherFiltering); + EditorGUI.indentLevel--; + } - // Sampling type - //EditorGUILayout.PropertyField(m_PvrSampling, Styles.m_PVRSampling); // TODO(PVR): make non-fixed sampling modes work. + EditorGUI.indentLevel--; + } - if (LightmapEditorSettings.sampling != LightmapEditorSettings.Sampling.Auto) + if (m_BakeBackend.intValue != (int)LightmapEditorSettings.Lightmapper.Enlighten) { - // Update those constants also in LightmapBake.cpp UpdateSamples() and LightmapBake.h. - // NOTE: sample count needs to be a power of two as we are using Sobol sequence. - const int kMinDirectSamples = 1; - const int kMinEnvironmentSamples = 8; - const int kMinSamples = 8; - const int kMaxSamples = 131072; - - // Sample count - // TODO(PVR): make non-fixed sampling modes work. - //EditorGUI.indentLevel++; - //if (LightmapEditorSettings.giPathTracerSampling == LightmapEditorSettings.PathTracerSampling.PathTracerSamplingAdaptive) - // EditorGUILayout.PropertyField(m_PVRSampleCount, Styles.PVRSampleCountAdaptive); - //else - - EditorGUILayout.PropertyField(m_PVRDirectSampleCount, Styles.PVRDirectSampleCount); - EditorGUILayout.PropertyField(m_PVRSampleCount, Styles.PVRIndirectSampleCount); - - if (m_PVRSampleCount.intValue < kMinSamples || - m_PVRSampleCount.intValue > kMaxSamples) - { - m_PVRSampleCount.intValue = Math.Max(Math.Min(m_PVRSampleCount.intValue, kMaxSamples), kMinSamples); - } + EditorGUI.indentLevel++; - if (m_PVRDirectSampleCount.intValue < kMinDirectSamples || - m_PVRDirectSampleCount.intValue > kMaxSamples) - { - m_PVRDirectSampleCount.intValue = Math.Max(Math.Min(m_PVRDirectSampleCount.intValue, kMaxSamples), kMinDirectSamples); - } + EditorGUILayout.PropertyField(m_PVRCulling, Styles.PVRCulling); - EditorGUILayout.PropertyField(m_PVREnvironmentSampleCount, Styles.PVREnvironmentSampleCount); + bool enableMIS = (m_PVREnvironmentMIS.intValue & 1) != 0; + if (EditorGUILayout.Toggle(Styles.PVREnvironmentMIS, enableMIS)) + m_PVREnvironmentMIS.intValue |= 1; + else + m_PVREnvironmentMIS.intValue &= ~1; - if (m_PVREnvironmentSampleCount.intValue < kMinEnvironmentSamples || m_PVREnvironmentSampleCount.intValue > kMaxSamples) + // Sampling type + //EditorGUILayout.PropertyField(m_PvrSampling, Styles.m_PVRSampling); // TODO(PVR): make non-fixed sampling modes work. + + if (LightmapEditorSettings.sampling != LightmapEditorSettings.Sampling.Auto) { - m_PVREnvironmentSampleCount.intValue = Math.Max(Math.Min(m_PVREnvironmentSampleCount.intValue, kMaxSamples), kMinEnvironmentSamples); - } + // Update those constants also in LightmapBake.cpp UpdateSamples() and LightmapBake.h. + // NOTE: sample count needs to be a power of two as we are using Sobol sequence. + const int kMinDirectSamples = 1; + const int kMinEnvironmentSamples = 8; + const int kMinSamples = 8; + const int kMaxSamples = 131072; + + // Sample count + // TODO(PVR): make non-fixed sampling modes work. + //EditorGUI.indentLevel++; + //if (LightmapEditorSettings.giPathTracerSampling == LightmapEditorSettings.PathTracerSampling.PathTracerSamplingAdaptive) + // EditorGUILayout.PropertyField(m_PVRSampleCount, Styles.PVRSampleCountAdaptive); + //else + + EditorGUILayout.PropertyField(m_PVRDirectSampleCount, Styles.PVRDirectSampleCount); + EditorGUILayout.PropertyField(m_PVRSampleCount, Styles.PVRIndirectSampleCount); + + if (m_PVRSampleCount.intValue < kMinSamples || + m_PVRSampleCount.intValue > kMaxSamples) + { + m_PVRSampleCount.intValue = Math.Max(Math.Min(m_PVRSampleCount.intValue, kMaxSamples), kMinSamples); + } - // TODO(PVR): make non-fixed sampling modes work. - //EditorGUI.indentLevel--; - } + if (m_PVRDirectSampleCount.intValue < kMinDirectSamples || + m_PVRDirectSampleCount.intValue > kMaxSamples) + { + m_PVRDirectSampleCount.intValue = Math.Max(Math.Min(m_PVRDirectSampleCount.intValue, kMaxSamples), kMinDirectSamples); + } - EditorGUILayout.IntPopup(m_PVRBounces, Styles.BouncesStrings, Styles.BouncesValues, Styles.PVRBounces); + EditorGUILayout.PropertyField(m_PVREnvironmentSampleCount, Styles.PVREnvironmentSampleCount); - // Filtering - EditorGUILayout.PropertyField(m_PVRFilteringMode, Styles.PVRFilteringMode); + if (m_PVREnvironmentSampleCount.intValue < kMinEnvironmentSamples || m_PVREnvironmentSampleCount.intValue > kMaxSamples) + { + m_PVREnvironmentSampleCount.intValue = Math.Max(Math.Min(m_PVREnvironmentSampleCount.intValue, kMaxSamples), kMinEnvironmentSamples); + } - if (m_PVRFilteringMode.enumValueIndex == (int)LightmapEditorSettings.FilterMode.Advanced) - { - // Check if the platform doesn't support denoising. - bool usingGPULightmapper = LightmapEditorSettings.lightmapper == LightmapEditorSettings.Lightmapper.ProgressiveGPU; - bool anyDenoisingSupported = (LightmapEditorSettings.IsOptixDenoiserSupported() || LightmapEditorSettings.IsOpenImageDenoiserSupported()); - bool aoDenoisingSupported = DenoiserSupported((LightmapEditorSettings.DenoiserType)m_PVRDenoiserTypeAO.intValue); - bool directDenoisingSupported = DenoiserSupported((LightmapEditorSettings.DenoiserType)m_PVRDenoiserTypeDirect.intValue); - bool indirectDenoisingSupported = DenoiserSupported((LightmapEditorSettings.DenoiserType)m_PVRDenoiserTypeIndirect.intValue); + using (new EditorGUI.DisabledScope(EditorSettings.useLegacyProbeSampleCount)) + { + EditorGUILayout.PropertyField(m_LightProbeSampleCountMultiplier, Styles.ProbeSampleCountMultiplier); + int directSampleCount = m_PVRDirectSampleCount.intValue; + int indirectSampleCount = m_PVRSampleCount.intValue; + int environmentSampleCount = m_PVREnvironmentSampleCount.intValue; + int maxSampleCount = Math.Max(directSampleCount, Math.Max(indirectSampleCount, environmentSampleCount)); + float maxMultiplier = (float)kMaxSamples / (float)maxSampleCount; + if (m_LightProbeSampleCountMultiplier.floatValue > maxMultiplier) + { + m_LightProbeSampleCountMultiplier.floatValue = Math.Min(m_LightProbeSampleCountMultiplier.floatValue, maxMultiplier); + if (m_LightProbeSampleCountMultiplier.floatValue > 2.0f) + m_LightProbeSampleCountMultiplier.floatValue = (float)Math.Floor((double)m_LightProbeSampleCountMultiplier.floatValue); + } + float minMultiplier = (float)kMinSamples / (float)maxSampleCount; + if (m_LightProbeSampleCountMultiplier.floatValue < minMultiplier) + { + m_LightProbeSampleCountMultiplier.floatValue = Math.Max(m_LightProbeSampleCountMultiplier.floatValue, minMultiplier); + } + } - EditorGUI.indentLevel++; - using (new EditorGUI.DisabledScope(!anyDenoisingSupported)) - { - DrawDenoiserTypeDropdown(m_PVRDenoiserTypeDirect, directDenoisingSupported ? Styles.PVRDenoiserTypeDirect : Styles.DenoisingWarningDirect, DenoiserTarget.Direct); + // TODO(PVR): make non-fixed sampling modes work. + //EditorGUI.indentLevel--; } - ClampFilterType(m_PVRFilterTypeDirect); - if (LightmapEditorSettings.lightmapper == LightmapEditorSettings.Lightmapper.ProgressiveGPU) - EditorGUILayout.IntPopup(m_PVRFilterTypeDirect, Styles.GPUFilterOptions, Styles.GPUFilterInts, Styles.PVRFilterTypeDirect); - else - EditorGUILayout.PropertyField(m_PVRFilterTypeDirect, Styles.PVRFilterTypeDirect); - EditorGUI.indentLevel++; - DrawFilterSettingField(m_PVRFilteringGaussRadiusDirect, - m_PVRFilteringAtrousPositionSigmaDirect, - Styles.PVRFilteringGaussRadiusDirect, - Styles.PVRFilteringAtrousPositionSigmaDirect, - LightmapEditorSettings.filterTypeDirect); - EditorGUI.indentLevel--; + EditorGUILayout.IntPopup(m_PVRBounces, Styles.BouncesStrings, Styles.BouncesValues, Styles.PVRBounces); - EditorGUILayout.Space(); + // Filtering + EditorGUILayout.PropertyField(m_PVRFilteringMode, Styles.PVRFilteringMode); - using (new EditorGUI.DisabledScope(!anyDenoisingSupported)) + if (m_PVRFilteringMode.enumValueIndex == (int)LightmapEditorSettings.FilterMode.Advanced) { - DrawDenoiserTypeDropdown(m_PVRDenoiserTypeIndirect, indirectDenoisingSupported ? Styles.PVRDenoiserTypeIndirect : Styles.DenoisingWarningIndirect, DenoiserTarget.Indirect); - } - if (LightmapEditorSettings.lightmapper == LightmapEditorSettings.Lightmapper.ProgressiveGPU) - EditorGUILayout.IntPopup(m_PVRFilterTypeIndirect, Styles.GPUFilterOptions, Styles.GPUFilterInts, Styles.PVRFilterTypeIndirect); - else - EditorGUILayout.PropertyField(m_PVRFilterTypeIndirect, Styles.PVRFilterTypeIndirect); - ClampFilterType(m_PVRFilterTypeIndirect); + // Check if the platform doesn't support denoising. + bool usingGPULightmapper = m_BakeBackend.intValue == (int)LightmapEditorSettings.Lightmapper.ProgressiveGPU; + bool anyDenoisingSupported = (LightmapEditorSettings.IsOptixDenoiserSupported() || LightmapEditorSettings.IsOpenImageDenoiserSupported() || LightmapEditorSettings.IsRadeonDenoiserSupported()); + bool aoDenoisingSupported = DenoiserSupported((LightmapEditorSettings.DenoiserType)m_PVRDenoiserTypeAO.intValue); + bool directDenoisingSupported = DenoiserSupported((LightmapEditorSettings.DenoiserType)m_PVRDenoiserTypeDirect.intValue); + bool indirectDenoisingSupported = DenoiserSupported((LightmapEditorSettings.DenoiserType)m_PVRDenoiserTypeIndirect.intValue); - EditorGUI.indentLevel++; - DrawFilterSettingField(m_PVRFilteringGaussRadiusIndirect, - m_PVRFilteringAtrousPositionSigmaIndirect, - Styles.PVRFilteringGaussRadiusIndirect, - Styles.PVRFilteringAtrousPositionSigmaIndirect, - LightmapEditorSettings.filterTypeIndirect); - EditorGUI.indentLevel--; + EditorGUI.indentLevel++; + using (new EditorGUI.DisabledScope(!anyDenoisingSupported)) + { + DrawDenoiserTypeDropdown(m_PVRDenoiserTypeDirect, directDenoisingSupported ? Styles.PVRDenoiserTypeDirect : Styles.DenoisingWarningDirect, DenoiserTarget.Direct); + } + ClampFilterType(m_PVRFilterTypeDirect); + if (m_BakeBackend.intValue == (int)LightmapEditorSettings.Lightmapper.ProgressiveGPU) + EditorGUILayout.IntPopup(m_PVRFilterTypeDirect, Styles.GPUFilterOptions, Styles.GPUFilterInts, Styles.PVRFilterTypeDirect); + else + EditorGUILayout.PropertyField(m_PVRFilterTypeDirect, Styles.PVRFilterTypeDirect); + + EditorGUI.indentLevel++; + DrawFilterSettingField(m_PVRFilteringGaussRadiusDirect, + m_PVRFilteringAtrousPositionSigmaDirect, + Styles.PVRFilteringGaussRadiusDirect, + Styles.PVRFilteringAtrousPositionSigmaDirect, + LightmapEditorSettings.filterTypeDirect); + EditorGUI.indentLevel--; - using (new EditorGUI.DisabledScope(!m_AmbientOcclusion.boolValue)) - { EditorGUILayout.Space(); + using (new EditorGUI.DisabledScope(!anyDenoisingSupported)) { - DrawDenoiserTypeDropdown(m_PVRDenoiserTypeAO, aoDenoisingSupported ? Styles.PVRDenoiserTypeAO : Styles.DenoisingWarningAO, DenoiserTarget.AO); + DrawDenoiserTypeDropdown(m_PVRDenoiserTypeIndirect, indirectDenoisingSupported ? Styles.PVRDenoiserTypeIndirect : Styles.DenoisingWarningIndirect, DenoiserTarget.Indirect); } - if (LightmapEditorSettings.lightmapper == LightmapEditorSettings.Lightmapper.ProgressiveGPU) - EditorGUILayout.IntPopup(m_PVRFilterTypeAO, Styles.GPUFilterOptions, Styles.GPUFilterInts, Styles.PVRFilterTypeAO); + if (m_BakeBackend.intValue == (int)LightmapEditorSettings.Lightmapper.ProgressiveGPU) + EditorGUILayout.IntPopup(m_PVRFilterTypeIndirect, Styles.GPUFilterOptions, Styles.GPUFilterInts, Styles.PVRFilterTypeIndirect); else - EditorGUILayout.PropertyField(m_PVRFilterTypeAO, Styles.PVRFilterTypeAO); - ClampFilterType(m_PVRFilterTypeAO); + EditorGUILayout.PropertyField(m_PVRFilterTypeIndirect, Styles.PVRFilterTypeIndirect); + ClampFilterType(m_PVRFilterTypeIndirect); EditorGUI.indentLevel++; - DrawFilterSettingField(m_PVRFilteringGaussRadiusAO, - m_PVRFilteringAtrousPositionSigmaAO, - Styles.PVRFilteringGaussRadiusAO, Styles.PVRFilteringAtrousPositionSigmaAO, - LightmapEditorSettings.filterTypeAO); + DrawFilterSettingField(m_PVRFilteringGaussRadiusIndirect, + m_PVRFilteringAtrousPositionSigmaIndirect, + Styles.PVRFilteringGaussRadiusIndirect, + Styles.PVRFilteringAtrousPositionSigmaIndirect, + LightmapEditorSettings.filterTypeIndirect); + EditorGUI.indentLevel--; + + using (new EditorGUI.DisabledScope(!m_AmbientOcclusion.boolValue)) + { + EditorGUILayout.Space(); + using (new EditorGUI.DisabledScope(!anyDenoisingSupported)) + { + DrawDenoiserTypeDropdown(m_PVRDenoiserTypeAO, aoDenoisingSupported ? Styles.PVRDenoiserTypeAO : Styles.DenoisingWarningAO, DenoiserTarget.AO); + } + if (m_BakeBackend.intValue == (int)LightmapEditorSettings.Lightmapper.ProgressiveGPU) + EditorGUILayout.IntPopup(m_PVRFilterTypeAO, Styles.GPUFilterOptions, Styles.GPUFilterInts, Styles.PVRFilterTypeAO); + else + EditorGUILayout.PropertyField(m_PVRFilterTypeAO, Styles.PVRFilterTypeAO); + ClampFilterType(m_PVRFilterTypeAO); + + EditorGUI.indentLevel++; + DrawFilterSettingField(m_PVRFilteringGaussRadiusAO, + m_PVRFilteringAtrousPositionSigmaAO, + Styles.PVRFilteringGaussRadiusAO, Styles.PVRFilteringAtrousPositionSigmaAO, + LightmapEditorSettings.filterTypeAO); + EditorGUI.indentLevel--; + } + // Show warning if A-Trous filtering is selected and the platform doesn't support it. + if (usingGPULightmapper && (m_PVRFilterTypeDirect.intValue == (int)LightmapEditorSettings.FilterType.ATrous || m_PVRFilterTypeIndirect.intValue == (int)LightmapEditorSettings.FilterType.ATrous || (m_AmbientOcclusion.boolValue && m_PVRFilterTypeAO.intValue == (int)LightmapEditorSettings.FilterType.ATrous))) + EditorGUILayout.HelpBox(Styles.ProgressiveGPUWarning.text, MessageType.Warning); + EditorGUI.indentLevel--; } - // Show warning if A-Trous filtering is selected and the platform doesn't support it. - if (usingGPULightmapper && (m_PVRFilterTypeDirect.intValue == (int)LightmapEditorSettings.FilterType.ATrous || m_PVRFilterTypeIndirect.intValue == (int)LightmapEditorSettings.FilterType.ATrous || (m_AmbientOcclusion.boolValue && m_PVRFilterTypeAO.intValue == (int)LightmapEditorSettings.FilterType.ATrous))) - EditorGUILayout.HelpBox(Styles.ProgressiveGPUWarning.text, MessageType.Warning); EditorGUI.indentLevel--; } - - EditorGUI.indentLevel--; } } } // We only want to show the Indirect Resolution in a disabled state if the user is using PLM and has the ability to turn on Realtime GI. - if (realtimeGISupported || (bakedGISupported && (LightmapEditorSettings.lightmapper == LightmapEditorSettings.Lightmapper.Enlighten))) + if (realtimeGISupported || (bakedGISupported && (m_BakeBackend.intValue == (int)LightmapEditorSettings.Lightmapper.Enlighten) && lightmapperSupported)) { - using (new EditorGUI.DisabledScope((LightmapEditorSettings.lightmapper != LightmapEditorSettings.Lightmapper.Enlighten) && !m_EnableRealtimeGI.boolValue)) + using (new EditorGUI.DisabledScope((m_BakeBackend.intValue != (int)LightmapEditorSettings.Lightmapper.Enlighten) && !m_EnableRealtimeGI.boolValue)) { DrawResolutionField(m_Resolution, Styles.IndirectResolution); } @@ -668,18 +751,6 @@ void GeneralLightmapSettingsGUI() EditorGUI.indentLevel--; } - - if (LightmapEditorSettings.lightmapper == LightmapEditorSettings.Lightmapper.Enlighten) - { - EditorGUILayout.PropertyField(m_FinalGather, Styles.FinalGather); - if (m_FinalGather.boolValue) - { - EditorGUI.indentLevel++; - EditorGUILayout.PropertyField(m_FinalGatherRayCount, Styles.FinalGatherRayCount); - EditorGUILayout.PropertyField(m_FinalGatherFiltering, Styles.FinalGatherFiltering); - EditorGUI.indentLevel--; - } - } } } @@ -738,6 +809,14 @@ public void OnGUI() static class Styles { + public static readonly int[] BakeBackendValues = { (int)LightmapEditorSettings.Lightmapper.Enlighten, (int)LightmapEditorSettings.Lightmapper.ProgressiveCPU, (int)LightmapEditorSettings.Lightmapper.ProgressiveGPU }; + public static readonly GUIContent[] BakeBackendStrings = + { + EditorGUIUtility.TrTextContent("Enlighten (Deprecated)"), + EditorGUIUtility.TrTextContent("Progressive CPU"), + EditorGUIUtility.TrTextContent("Progressive GPU (Preview)"), + }; + public static readonly int[] LightmapDirectionalModeValues = { (int)LightmapsMode.NonDirectional, (int)LightmapsMode.CombinedDirectional }; public static readonly GUIContent[] LightmapDirectionalModeStrings = { @@ -766,11 +845,12 @@ static class Styles }; // must match PVRDenoiserType - public static readonly int[] DenoiserTypeValues = { (int)LightmapEditorSettings.DenoiserType.Optix, (int)LightmapEditorSettings.DenoiserType.OpenImage, (int)LightmapEditorSettings.DenoiserType.None }; + public static readonly int[] DenoiserTypeValues = { (int)LightmapEditorSettings.DenoiserType.Optix, (int)LightmapEditorSettings.DenoiserType.OpenImage, (int)LightmapEditorSettings.DenoiserType.RadeonPro, (int)LightmapEditorSettings.DenoiserType.None }; public static readonly GUIContent[] DenoiserTypeStrings = { EditorGUIUtility.TrTextContent("Optix"), EditorGUIUtility.TrTextContent("OpenImageDenoise"), + EditorGUIUtility.TrTextContent("Radeon Pro"), EditorGUIUtility.TrTextContent("None") }; @@ -791,6 +871,7 @@ static class Styles EditorGUIUtility.TrTextContent("Mixed lights provide realtime direct lighting. Indirect lighting gets baked into lightmaps and light probes. Shadowmasks and light probes occlusion get generated for baked shadows. The Shadowmask Mode used at run time can be set in the Quality Settings panel.") }; + public static readonly GUIContent LightmapperNotSupportedWarning = EditorGUIUtility.TrTextContent("The Lightmapper is not supported by the current render pipeline. Fallback is "); public static readonly GUIContent MixedModeNotSupportedWarning = EditorGUIUtility.TrTextContent("The Mixed mode is not supported by the current render pipeline. Fallback mode is "); public static readonly GUIContent DirectionalNotSupportedWarning = EditorGUIUtility.TrTextContent("Directional Mode is not supported. Fallback will be Non-Directional."); @@ -825,7 +906,7 @@ 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 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."); @@ -853,6 +934,7 @@ static class Styles 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 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."); + public static readonly GUIContent ProbeSampleCountMultiplier = EditorGUIUtility.TrTextContent("Light Probe Sample Multiplier", "Controls how many samples are used for Light Probes as a multiplier of the general sample counts above. Higher values improve the quality of Light Probes, but also take longer to bake. Enable the Light Probe sample count multiplier in the Editor tab under Project Settings."); // 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") }; public static readonly int[] GPUFilterInts = new[] { (int)LightmapEditorSettings.FilterType.Gaussian, (int)LightmapEditorSettings.FilterType.None }; diff --git a/Editor/Mono/SceneModeWindows/LightingWindowLightingTab.cs b/Editor/Mono/SceneModeWindows/LightingWindowLightingTab.cs index 34ae986c71..c517df122f 100644 --- a/Editor/Mono/SceneModeWindows/LightingWindowLightingTab.cs +++ b/Editor/Mono/SceneModeWindows/LightingWindowLightingTab.cs @@ -4,21 +4,23 @@ using System; using System.Collections.Generic; -using System.Collections; -using System.Linq; using System.Text; -using UnityEditor.AnimatedValues; -using UnityEditor.SceneManagement; using UnityEditorInternal; using UnityEngine; -using UnityEngine.SceneManagement; -using UnityEngineInternal; using Object = UnityEngine.Object; using UnityEngine.Rendering; +using UnityEditor.Rendering; using System.Globalization; namespace UnityEditor { + public abstract class LightingWindowEnvironmentSection + { + public virtual void OnEnable() {} + public virtual void OnDisable() {} + public virtual void OnInspectorGUI() {} + } + internal class LightingWindowLightingTab { class Styles @@ -41,13 +43,45 @@ class Styles public static readonly float ButtonWidth = 90; } + class DefaultEnvironmentSectionExtension : LightingWindowEnvironmentSection + { + Editor m_EnvironmentEditor; + + Editor environmentEditor + { + get + { + if (m_EnvironmentEditor == null || m_EnvironmentEditor.target == null) + { + Editor.CreateCachedEditor(RenderSettings.GetRenderSettings(), typeof(LightingEditor), ref m_EnvironmentEditor); + } + + return m_EnvironmentEditor; + } + } + + public override void OnInspectorGUI() + { + environmentEditor.OnInspectorGUI(); + } + + public override void OnDisable() + { + if (m_EnvironmentEditor != null) + { + Object.DestroyImmediate(m_EnvironmentEditor); + m_EnvironmentEditor = null; + } + } + } + enum BakeMode { BakeReflectionProbes = 0, Clear = 1 } - Editor m_LightingEditor; + LightingWindowEnvironmentSection m_EnvironmentSection; Editor m_FogEditor; Editor m_OtherRenderingEditor; SavedBool m_ShowOtherSettings; @@ -62,6 +96,8 @@ enum BakeMode SerializedProperty m_WorkflowMode; SerializedProperty m_EnabledBakedGI; + Type m_SRP = GraphicsSettings.currentRenderPipeline?.GetType(); + Object renderSettings { get @@ -73,16 +109,29 @@ Object renderSettings } } - Editor lightingEditor + LightingWindowEnvironmentSection environmentEditor { get { - if (m_LightingEditor == null || m_LightingEditor.target == null) + var currentSRP = GraphicsSettings.currentRenderPipeline?.GetType(); + if (m_EnvironmentSection != null && m_SRP != currentSRP) + { + m_SRP = currentSRP; + m_EnvironmentSection.OnDisable(); + m_EnvironmentSection = null; + } + + if (m_EnvironmentSection == null) { - Editor.CreateCachedEditor(renderSettings, typeof(LightingEditor), ref m_LightingEditor); + Type extensionType = RenderPipelineEditorUtility.FetchFirstCompatibleTypeUsingScriptableRenderPipelineExtension(); + if (extensionType == null) + extensionType = typeof(DefaultEnvironmentSectionExtension); + LightingWindowEnvironmentSection extension = (LightingWindowEnvironmentSection)Activator.CreateInstance(extensionType); + m_EnvironmentSection = extension; + m_EnvironmentSection.OnEnable(); } - return m_LightingEditor; + return m_EnvironmentSection; } } @@ -127,16 +176,17 @@ public void OnEnable() public void OnDisable() { m_BakeSettings.OnDisable(); + environmentEditor.OnDisable(); ClearCachedProperties(); } void ClearCachedProperties() { - if (m_LightingEditor != null) + if (m_EnvironmentSection != null) { - Object.DestroyImmediate(m_LightingEditor); - m_LightingEditor = null; + m_EnvironmentSection.OnDisable(); + m_EnvironmentSection = null; } if (m_FogEditor != null) { @@ -209,7 +259,7 @@ public void OnGUI() m_ScrollPosition = EditorGUILayout.BeginScrollView(m_ScrollPosition); if (!SupportedRenderingFeatures.active.overridesEnvironmentLighting) - lightingEditor.OnInspectorGUI(); + environmentEditor.OnInspectorGUI(); m_BakeSettings.OnGUI(); OtherSettingsGUI(); diff --git a/Editor/Mono/SceneModeWindows/NavigationWindow.cs b/Editor/Mono/SceneModeWindows/NavigationWindow.cs index 183bd82917..732f6c9bbd 100644 --- a/Editor/Mono/SceneModeWindows/NavigationWindow.cs +++ b/Editor/Mono/SceneModeWindows/NavigationWindow.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; -using System.Linq; using UnityEngine; using UnityEngine.AI; using UnityEditor.AI; @@ -455,8 +454,7 @@ public void OnBecameInvisible() static void RepaintSceneAndGameViews() { SceneView.RepaintAll(); - foreach (GameView gv in Resources.FindObjectsOfTypeAll(typeof(GameView))) - gv.Repaint(); + PreviewEditorWindow.RepaintAll(); } public void OnSceneViewGUI(SceneView sceneView) @@ -684,11 +682,6 @@ static List GetObjects(bool includeChildren) return new List(Selection.gameObjects); } - static bool SelectionHasChildren() - { - return Selection.gameObjects.Any(obj => obj.transform.childCount > 0); - } - static void SetNavMeshArea(int area, bool includeChildren) { var objects = GetObjects(includeChildren); diff --git a/Editor/Mono/SceneView/SceneView.cs b/Editor/Mono/SceneView/SceneView.cs index 294e7b3ed8..6717365b3f 100644 --- a/Editor/Mono/SceneView/SceneView.cs +++ b/Editor/Mono/SceneView/SceneView.cs @@ -21,6 +21,7 @@ using Object = UnityEngine.Object; using RequiredByNativeCodeAttribute = UnityEngine.Scripting.RequiredByNativeCodeAttribute; using UnityEditor.EditorTools; +using UnityEditor.Snap; namespace UnityEditor { @@ -209,7 +210,6 @@ protected internal Transform customParentForDraggedObjects static readonly Quaternion kDefaultRotation = Quaternion.LookRotation(new Vector3(-1, -.7f, -1)); const float kDefaultViewSize = 10f; - const CameraEvent kCommandBufferCameraEvent = CameraEvent.AfterImageEffectsOpaque; [NonSerialized] static readonly Vector3 kDefaultPivot = Vector3.zero; @@ -239,7 +239,8 @@ public bool sceneLighting } public event Func onValidateCameraMode; - public event Action onCameraModeChanged; + public event Action onCameraModeChanged; + public event Action gridVisibilityChanged; [Serializable] public class SceneViewState @@ -318,8 +319,6 @@ public bool isRotationLocked internal static List userDefinedModes { get; } = new List(); - internal Object m_OneClickDragObject; - [SerializeField] bool m_PlayAudio = false; @@ -437,6 +436,21 @@ public SceneViewState sceneViewState [SerializeField] SceneViewGrid grid; + + public bool showGrid + { + get { return grid.showGrid; } + set + { + if (grid.showGrid != value) + { + grid.showGrid = value; + if (gridVisibilityChanged != null) + gridVisibilityChanged(grid.showGrid); + } + } + } + [SerializeField] internal SceneViewRotation svRot; [SerializeField] @@ -652,15 +666,19 @@ public CameraSettings cameraSettings set { m_CameraSettings = value; } } + internal SceneViewGrid sceneViewGrids + { + get { return grid; } + } + public void ResetCameraSettings() { m_CameraSettings = new CameraSettings(); } - [SerializeField] - bool m_ShowGlobalGrid = true; - internal bool showGlobalGrid { get { return m_ShowGlobalGrid; } set { m_ShowGlobalGrid = value; } } - internal bool drawGlobalGrid { get { return AnnotationUtility.showGrid && showGlobalGrid; } } + // Thomas Tu: 2019-06-20. Will be marked as Obsolete. + // We need to deal with code dependency in packages first. + internal bool showGlobalGrid { get { return showGrid; } set { showGrid = value; } } [SerializeField] private Quaternion m_LastSceneViewRotation; @@ -751,6 +769,10 @@ internal static class Styles public static GUIContent gizmosContent = EditorGUIUtility.TrTextContent("Gizmos", "Toggle visibility of all Gizmos in the Scene view"); public static GUIContent gizmosDropDownContent = EditorGUIUtility.TrTextContent("", "Toggle the visibility of different Gizmos in the Scene view."); public static GUIContent mode2DContent = EditorGUIUtility.TrIconContent("SceneView2D", "When toggled on, the Scene is in 2D view. When toggled off, the Scene is in 3D view."); + public static GUIContent gridXToolbarContent = EditorGUIUtility.TrIconContent("SceneViewGridPopup_X", "Toggle the visibility of the grid"); + public static GUIContent gridYToolbarContent = EditorGUIUtility.TrIconContent("SceneViewGridPopup_Y", "Toggle the visibility of the grid"); + public static GUIContent gridZToolbarContent = EditorGUIUtility.TrIconContent("SceneViewGridPopup_Z", "Toggle the visibility of the grid"); + public static GUIContent snapMoveValue = EditorGUIUtility.TrIconContent("SnapModeGrid", "Toggle snapping on or off."); public static GUIContent isolationModeOverlayContent = EditorGUIUtility.TrTextContent("Isolation View", ""); public static GUIContent isolationModeExitButton = EditorGUIUtility.TrTextContent("Exit", "Exit isolation mode"); public static GUIContent renderDocContent; @@ -893,10 +915,10 @@ internal override void SetSearchFilter(string searchFilter, SearchMode mode, boo internal void OnLostFocus() { // don't bleed our scene view rendering into game view - GameView gameView = (GameView)WindowLayout.FindEditorWindowOfType(typeof(GameView)); - if (gameView && gameView.m_Parent != null && m_Parent != null && gameView.m_Parent == m_Parent) + var previewWindow = PreviewEditorWindow.GetMainPreviewWindow(); + if (previewWindow && previewWindow.m_Parent != null && m_Parent != null && previewWindow.m_Parent == m_Parent) { - gameView.m_Parent.backgroundValid = false; + previewWindow.m_Parent.backgroundValid = false; } if (s_LastActiveSceneView == this) @@ -907,9 +929,13 @@ public override void OnEnable() { titleContent = GetLocalizedTitleContent(); m_RectSelection = new RectSelection(this); + if (grid == null) grid = new SceneViewGrid(); + grid.OnEnable(); grid.Register(this); + ResetGrid(); + if (svRot == null) svRot = new SceneViewRotation(); svRot.Register(this); @@ -1161,6 +1187,64 @@ void ToolbarDisplayStateGUI() sceneViewState.SetAllEnabled(allOn); } + void ToolbarGridDropdownGUI() + { + bool toggled = grid.showGrid; + + GUIContent gridIcon = GUIContent.none; + switch (grid.gridAxis) + { + case SceneViewGrid.GridRenderAxis.X: + gridIcon = Styles.gridXToolbarContent; + break; + + case SceneViewGrid.GridRenderAxis.Y: + gridIcon = Styles.gridYToolbarContent; + break; + + case SceneViewGrid.GridRenderAxis.Z: + gridIcon = Styles.gridZToolbarContent; + break; + } + + EditorGUI.BeginChangeCheck(); + if (EditorGUILayout.DropDownToggle(ref toggled, gridIcon, EditorStyles.toolbarDropDownToggle)) + { + Rect rect = GUILayoutUtility.topLevel.GetLast(); + PopupWindow.Show(rect, new GridSettingsWindow(this)); + GUIUtility.ExitGUI(); + } + + if (EditorGUI.EndChangeCheck()) + grid.showGrid = toggled; + } + + void ToolbarSnapSettingsDropdownGUI() + { + bool toggled = EditorSnapSettings.enabled; + + GUIContent content = Styles.snapMoveValue; + + content.text = GetSnapMoveValueString("#.##"); + + if (EditorGUILayout.DropDownToggle(ref toggled, content, EditorStyles.toolbarDropDownToggle)) + { + Rect rect = GUILayoutUtility.topLevel.GetLast(); + PopupWindow.Show(rect, new SnapSettingsWindow()); + GUIUtility.ExitGUI(); + } + + EditorSnapSettings.enabled = toggled; + } + + string GetSnapMoveValueString(string format) + { + if (SnapSettingsWindow.IsMoveSnapValueMixed()) + return EditorGUI.mixedValueContent.text; + + return EditorSnapSettings.move.x.ToString(format, CultureInfo.InvariantCulture); + } + void ToolbarGizmosDropdownGUI() { bool toggled = drawGizmos; @@ -1225,9 +1309,11 @@ void DoToolbarGUI() { ToolbarDisplayStateGUI(); ToolbarSceneVisibilityGUI(); + ToolbarGridDropdownGUI(); GUILayout.FlexibleSpace(); + ToolbarSnapSettingsDropdownGUI(); ToolbarRenderDocGUI(); ToolbarSceneToolsGUI(); ToolbarSceneCameraGUI(); @@ -1730,7 +1816,7 @@ private void DoDrawCamera(Rect windowSpaceCameraRect, Rect groupSpaceCameraRect, bool oldAsync = ShaderUtil.allowAsyncCompilation; ShaderUtil.allowAsyncCompilation = EditorSettings.asyncShaderCompilation; - DrawGridParameters gridParam = grid.PrepareGridRender(camera, pivot, m_Rotation.target, size, m_Ortho.target, drawGlobalGrid); + DrawGridParameters gridParam = grid.PrepareGridRender(camera, pivot, m_Rotation.target, size, m_Ortho.target); Event evt = Event.current; if (UseSceneFiltering()) @@ -1759,6 +1845,7 @@ private void DoDrawCamera(Rect windowSpaceCameraRect, Rect groupSpaceCameraRect, pushedGUIClip = true; } Handles.DrawCameraStep1(groupSpaceCameraRect, m_Camera, m_CameraMode.drawMode, gridParam, drawGizmos); + DrawRenderModeOverlay(groupSpaceCameraRect); } ShaderUtil.allowAsyncCompilation = oldAsync; @@ -3474,10 +3561,13 @@ void CallOnSceneGUI() if (EditorGUI.EndChangeCheck()) editor.serializedObject.SetIsDifferentCacheDirty(); } + ResetOnSceneGUIState(); } } + EditorToolContext.InvokeOnSceneGUICustomEditorTools(); + if (duringSceneGui != null) { ResetOnSceneGUIState(); @@ -3580,10 +3670,10 @@ static void ShowCompileErrorNotification() internal static void ShowSceneViewPlayModeSaveWarning() { - // In this case, we wan't to explicitely try the GameView before passing it on to whatever notificationView we have - var gameView = (GameView)WindowLayout.FindEditorWindowOfType(typeof(GameView)); - if (gameView != null && gameView.hasFocus) - gameView.ShowNotification(EditorGUIUtility.TrTextContent("You must exit play mode to save the scene!")); + // In this case, we want to explicitly try the GameView before passing it on to whatever notificationView we have + var preview = (PreviewEditorWindow)WindowLayout.FindEditorWindowOfType(typeof(PreviewEditorWindow)); + if (preview != null && preview.hasFocus) + preview.ShowNotification(EditorGUIUtility.TrTextContent("You must exit play mode to save the scene!")); else ShowNotification("You must exit play mode to save the scene!"); } @@ -3622,7 +3712,7 @@ private void On2DModeChange() { if (m_2DMode) { - lastSceneViewRotation = rotation; + lastSceneViewRotation = m_Rotation.target; m_LastSceneViewOrtho = orthographic; LookAt(pivot, Quaternion.identity, size, true); if (Tools.current == Tool.Move) @@ -3683,5 +3773,10 @@ public static CameraMode GetBuiltinCameraMode(DrawCameraMode mode) { return SceneRenderModeWindow.GetBuiltinCameraMode(mode); } + + internal void ResetGrid() + { + grid.SetAllGridsPivot(Vector3.zero); + } } } // namespace diff --git a/Editor/Mono/SceneView/SceneViewGrid.cs b/Editor/Mono/SceneView/SceneViewGrid.cs index c379b01ad2..869a272209 100644 --- a/Editor/Mono/SceneView/SceneViewGrid.cs +++ b/Editor/Mono/SceneView/SceneViewGrid.cs @@ -4,37 +4,172 @@ using UnityEditor.AnimatedValues; using UnityEngine; -using UnityEditor; -using System.Collections; +using UnityEditor.Snap; namespace UnityEditor { [System.Serializable] internal class SceneViewGrid { - static PrefColor kViewGridColor = new PrefColor("Scene/Grid", .5f, .5f, .5f, .4f); + internal enum GridRenderAxis + { + X, + Y, + Z, + All + } - public void Register(SceneView source) + [System.Serializable] + internal class Grid { - // hook up the anims, so repainting can work correctly - xGrid.valueChanged.AddListener(source.Repaint); - yGrid.valueChanged.AddListener(source.Repaint); - zGrid.valueChanged.AddListener(source.Repaint); + [SerializeField] + AnimBool m_Fade = new AnimBool(); + + [SerializeField] + Color m_Color; + + [SerializeField] + Vector3 m_Pivot; + + [SerializeField] + Vector2 m_Size; + + internal AnimBool fade + { + get { return m_Fade; } + set { m_Fade = value; } + } + + internal Color color + { + get { return m_Color; } + set { m_Color = value; } + } + + internal Vector3 pivot + { + get { return m_Pivot; } + set { m_Pivot = value; } + } + + internal Vector2 size + { + get { return m_Size; } + set { m_Size = value; } + } + + internal DrawGridParameters PrepareGridRender(int gridID, float opacity) + { + DrawGridParameters parameters = default(DrawGridParameters); + parameters.gridID = gridID; + parameters.pivot = pivot; + parameters.color = color; + parameters.color.a = fade.faded * opacity; + parameters.size = size; + + return parameters; + } } + internal static PrefColor kViewGridColor = new PrefColor("Scene/Grid", .5f, .5f, .5f, .4f); + static float k_AngleThresholdForOrthographicGrid = 0.15f; + [SerializeField] - AnimBool xGrid = new AnimBool(); + Grid xGrid = new Grid(); + [SerializeField] - AnimBool yGrid = new AnimBool(); + Grid yGrid = new Grid(); + [SerializeField] - AnimBool zGrid = new AnimBool(); + Grid zGrid = new Grid(); - public DrawGridParameters PrepareGridRender(Camera camera, Vector3 pivot, Quaternion rotation, - float size, bool orthoMode, bool gridVisible - ) + [SerializeField] + bool m_ShowGrid = true; + + [SerializeField] + GridRenderAxis m_GridAxis = GridRenderAxis.Y; + + [SerializeField] + float m_gridOpacity = 1.0f; + + internal bool showGrid + { + get { return m_ShowGrid; } + set { m_ShowGrid = value; } + } + + internal float gridOpacity + { + get { return m_gridOpacity; } + set { m_gridOpacity = Mathf.Clamp01(value); } + } + + internal GridRenderAxis gridAxis + { + get { return m_GridAxis; } + set { m_GridAxis = value; } + } + + internal Grid activeGrid + { + get + { + if (gridAxis == GridRenderAxis.X) + return xGrid; + else if (gridAxis == GridRenderAxis.Y) + return yGrid; + else if (gridAxis == GridRenderAxis.Z) + return zGrid; + return yGrid; + } + } + + internal void OnEnable() + { + xGrid.color = yGrid.color = zGrid.color = kViewGridColor; + } + + internal void Register(SceneView source) + { + // hook up the anims, so repainting can work correctly + xGrid.fade.valueChanged.AddListener(source.Repaint); + yGrid.fade.valueChanged.AddListener(source.Repaint); + zGrid.fade.valueChanged.AddListener(source.Repaint); + } + + internal void SetAllGridsPivot(Vector3 pivot) + { + xGrid.pivot = pivot; + yGrid.pivot = pivot; + zGrid.pivot = pivot; + } + + internal void SetPivot(GridRenderAxis axis, Vector3 pivot) + { + if (axis == GridRenderAxis.X) + xGrid.pivot = pivot; + else if (axis == GridRenderAxis.Y) + yGrid.pivot = pivot; + else if (axis == GridRenderAxis.Z) + zGrid.pivot = pivot; + } + + internal Vector3 GetPivot(GridRenderAxis axis) + { + if (axis == GridRenderAxis.X) + return xGrid.pivot; + else if (axis == GridRenderAxis.Y) + return yGrid.pivot; + else if (axis == GridRenderAxis.Z) + return zGrid.pivot; + return Vector3.zero; + } + + internal void UpdateGridsVisibility(Quaternion rotation, bool orthoMode) { bool _xGrid = false, _yGrid = false, _zGrid = false; - if (gridVisible) + + if (showGrid) { if (orthoMode) { @@ -50,22 +185,112 @@ public DrawGridParameters PrepareGridRender(Camera camera, Vector3 pivot, Quater } else { - _yGrid = true; + _xGrid = (gridAxis == GridRenderAxis.X || gridAxis == GridRenderAxis.All); + _yGrid = (gridAxis == GridRenderAxis.Y || gridAxis == GridRenderAxis.All); + _zGrid = (gridAxis == GridRenderAxis.Z || gridAxis == GridRenderAxis.All); } } - xGrid.target = _xGrid; - yGrid.target = _yGrid; - zGrid.target = _zGrid; + xGrid.fade.target = _xGrid; + yGrid.fade.target = _yGrid; + zGrid.fade.target = _zGrid; + } + + internal void ApplySnapConstraintsInPerspectiveMode() + { + switch (gridAxis) + { + case GridRenderAxis.X: + ApplySnapContraintsOnXAxis(); + break; + case GridRenderAxis.Y: + ApplySnapContraintsOnYAxis(); + break; + case GridRenderAxis.Z: + ApplySnapContraintsOnZAxis(); + break; + } + } + + internal void ApplySnapConstraintsInOrthogonalMode() + { + if (xGrid.fade.target) + ApplySnapContraintsOnXAxis(); + if (yGrid.fade.target) + ApplySnapContraintsOnYAxis(); + if (zGrid.fade.target) + ApplySnapContraintsOnZAxis(); + } + + void ApplySnapContraintsOnXAxis() + { + xGrid.size = new Vector2(EditorSnapSettings.move.y, EditorSnapSettings.move.z); + } + + void ApplySnapContraintsOnYAxis() + { + yGrid.size = new Vector2(EditorSnapSettings.move.z, EditorSnapSettings.move.x); + } + + void ApplySnapContraintsOnZAxis() + { + zGrid.size = new Vector2(EditorSnapSettings.move.x, EditorSnapSettings.move.y); + } + + internal DrawGridParameters PrepareGridRender(Camera camera, Vector3 pivot, Quaternion rotation, + float size, bool orthoMode) + { + UpdateGridsVisibility(rotation, orthoMode); + + if (orthoMode) + { + ApplySnapConstraintsInOrthogonalMode(); + return PrepareGridRenderOrthogonalMode(camera, pivot, rotation, size); + } + + ApplySnapConstraintsInPerspectiveMode(); + return PrepareGridRenderPerspectiveMode(camera, pivot, rotation, size); + } + + internal DrawGridParameters PrepareGridRenderPerspectiveMode(Camera camera, Vector3 pivot, Quaternion rotation, + float size) + { + DrawGridParameters parameters = default(DrawGridParameters); + + switch (gridAxis) + { + case GridRenderAxis.X: + parameters = xGrid.PrepareGridRender(0, gridOpacity); + break; + case GridRenderAxis.Y: + parameters = yGrid.PrepareGridRender(1, gridOpacity); + break; + case GridRenderAxis.Z: + parameters = zGrid.PrepareGridRender(2, gridOpacity); + break; + } + + return parameters; + } + + internal DrawGridParameters PrepareGridRenderOrthogonalMode(Camera camera, Vector3 pivot, Quaternion rotation, + float size) + { + Vector3 direction = camera.transform.TransformDirection(new Vector3(0, 0, 1)); - DrawGridParameters parameters; - parameters.pivot = pivot; - parameters.color = kViewGridColor; - parameters.size = size; - parameters.alphaX = xGrid.faded; - parameters.alphaY = yGrid.faded; - parameters.alphaZ = zGrid.faded; + DrawGridParameters parameters = default(DrawGridParameters); + // Don't show orthographic grid at very shallow angles because it looks bad. + // It's normally already faded out by the managed animated fading values at this angle, + // but if it's orbited rapidly, it can end up at this angle faster than the fading has kicked in. + // For these cases hiding it abruptly looks better. + // The popping isn't noticable because the user is orbiting rapidly to begin with. + if (Mathf.Abs(direction.x) >= k_AngleThresholdForOrthographicGrid) + parameters = xGrid.PrepareGridRender(0, gridOpacity); + else if (Mathf.Abs(direction.y) >= k_AngleThresholdForOrthographicGrid) + parameters = yGrid.PrepareGridRender(1, gridOpacity); + else if (Mathf.Abs(direction.z) >= k_AngleThresholdForOrthographicGrid) + parameters = zGrid.PrepareGridRender(2, gridOpacity); return parameters; } diff --git a/Editor/Mono/SceneView/SceneViewPicking.cs b/Editor/Mono/SceneView/SceneViewPicking.cs index 9c83d61c48..0e18fb53a5 100644 --- a/Editor/Mono/SceneView/SceneViewPicking.cs +++ b/Editor/Mono/SceneView/SceneViewPicking.cs @@ -141,13 +141,18 @@ public static GameObject PickGameObject(Vector2 mousePosition) private static IEnumerable GetAllOverlapping(Vector2 position) { var allOverlapping = new List(); + var ignoreList = new List(); while (true) { - var go = HandleUtility.PickGameObject(position, false, allOverlapping.ToArray()); + var go = HandleUtility.PickGameObject(position, false, ignoreList.ToArray()); if (go == null) break; - + if (SceneVisibilityManager.instance.IsPickingDisabled(go)) + { + ignoreList.Add(go); + continue; + } // Prevent infinite loop if game object cannot be ignored when picking (This needs to fixed so print an error) if (allOverlapping.Count > 0 && go == allOverlapping.Last()) { @@ -158,6 +163,7 @@ private static IEnumerable GetAllOverlapping(Vector2 position) yield return go; allOverlapping.Add(go); + ignoreList.Add(go); } } diff --git a/Editor/Mono/SceneView/SceneViewStageHandling.cs b/Editor/Mono/SceneView/SceneViewStageHandling.cs index a620e266e3..ea2c399aa3 100644 --- a/Editor/Mono/SceneView/SceneViewStageHandling.cs +++ b/Editor/Mono/SceneView/SceneViewStageHandling.cs @@ -28,12 +28,6 @@ public bool isShowingBreadcrumbBar public float breadcrumbHeight { get { return BreadcrumbBar.DefaultStyles.background.fixedHeight; }} - static bool autoSave - { - get { return StageNavigationManager.instance.autoSave; } - set { StageNavigationManager.instance.autoSave = value; } - } - static class Styles { public static GUIContent autoSaveGUIContent = EditorGUIUtility.TrTextContent("Auto Save", "When Auto Save is enabled, every change you make is automatically saved to the Prefab Asset. Disable Auto Save if you experience long import times."); diff --git a/Editor/Mono/SceneView/SceneVisibilityState.bindings.cs b/Editor/Mono/SceneView/SceneVisibilityState.bindings.cs index fede197336..224b05451f 100644 --- a/Editor/Mono/SceneView/SceneVisibilityState.bindings.cs +++ b/Editor/Mono/SceneView/SceneVisibilityState.bindings.cs @@ -30,21 +30,31 @@ internal class SceneVisibilityState : Object public static extern bool IsHierarchyHidden([NotNull] GameObject gameObject); + public static extern void SetGameObjectPickingDisabled([NotNull] GameObject gameObject, bool pickingDisabled, bool includeChildren); + + public static extern void SetGameObjectsPickingDisabled([NotNull] GameObject[] gameObjects, bool pickingDisabled, bool includeChildren); + + public static extern bool IsGameObjectPickingDisabled([NotNull] GameObject gameObject); + + public static extern bool IsHierarchyPickingDisabled([NotNull] GameObject gameObject); public static extern bool AreAllChildrenVisible([NotNull] GameObject gameObject); + public static extern bool IsPickingEnabledOnAllChildren([NotNull] GameObject gameObject); public static extern bool AreAllChildrenHidden([NotNull] GameObject gameObject); + public static extern bool IsPickingDisabledOnAllChildren([NotNull] GameObject gameObject); public static extern void ShowScene(Scene scene); public static extern void HideScene(Scene scene); - public static extern bool HasHiddenGameObjects(Scene scene); + public static extern void EnablePicking(Scene scene); - public static extern void ClearScene(Scene scene); + public static extern void DisablePicking(Scene scene); - public static extern void SetSceneIsolation(Scene scene, bool isolating); + public static extern bool HasHiddenGameObjects(Scene scene); + public static extern bool ContainsGameObjectsWithPickingDisabled(Scene scene); - public static extern void ClearIsolation(); + public static extern void ClearScene(Scene scene); public static extern void OnSceneSaving(Scene scene, string scenePath); @@ -55,6 +65,7 @@ internal class SceneVisibilityState : Object public static extern void OnSceneSaved(Scene scene); public static extern int GetHiddenObjectCount(); + public static extern int GetPickingDisabledObjectCount(); public static extern void SetPrefabStageScene(Scene scene); public static Action internalStructureChanged; @@ -65,8 +76,8 @@ private static void Internal_InternalStructureChanged() internalStructureChanged?.Invoke(); } - public static extern bool active { get; set; } - public static extern bool prefabStageIsolated { get; set; } - public static extern bool mainStageIsolated { get; set; } + public static extern bool visibilityActive { get; set; } + public static extern bool pickingActive { get; set; } + public static extern bool isolation { get; set; } } } diff --git a/Editor/Mono/SceneVisibilityHierarchyGUI.cs b/Editor/Mono/SceneVisibilityHierarchyGUI.cs index 7af5094d22..30b3a316b6 100644 --- a/Editor/Mono/SceneVisibilityHierarchyGUI.cs +++ b/Editor/Mono/SceneVisibilityHierarchyGUI.cs @@ -20,6 +20,10 @@ public class IconState public GUIContent visibleMixed; public GUIContent hiddenAll; public GUIContent hiddenMixed; + public GUIContent pickingEnabledAll; + public GUIContent pickingEnabledMixed; + public GUIContent pickingDisabledAll; + public GUIContent pickingDisabledMixed; } public static readonly IconState iconNormal = new IconState @@ -28,6 +32,10 @@ public class IconState visibleMixed = EditorGUIUtility.TrIconContent("scenevis_visible-mixed"), hiddenAll = EditorGUIUtility.TrIconContent("scenevis_hidden"), hiddenMixed = EditorGUIUtility.TrIconContent("scenevis_hidden-mixed"), + pickingEnabledAll = EditorGUIUtility.TrIconContent("scenepicking_pickable"), + pickingEnabledMixed = EditorGUIUtility.TrIconContent("scenepicking_pickable-mixed"), + pickingDisabledAll = EditorGUIUtility.TrIconContent("scenepicking_notpickable"), + pickingDisabledMixed = EditorGUIUtility.TrIconContent("scenepicking_notpickable-mixed"), }; public static readonly IconState iconHovered = new IconState @@ -36,6 +44,10 @@ public class IconState visibleMixed = EditorGUIUtility.TrIconContent("scenevis_visible-mixed_hover"), hiddenAll = EditorGUIUtility.TrIconContent("scenevis_hidden_hover"), hiddenMixed = EditorGUIUtility.TrIconContent("scenevis_hidden-mixed_hover"), + pickingEnabledAll = EditorGUIUtility.TrIconContent("scenepicking_pickable_hover"), + pickingEnabledMixed = EditorGUIUtility.TrIconContent("scenepicking_pickable-mixed_hover"), + pickingDisabledAll = EditorGUIUtility.TrIconContent("scenepicking_notpickable_hover"), + pickingDisabledMixed = EditorGUIUtility.TrIconContent("scenepicking_notpickable-mixed_hover"), }; public static readonly Color backgroundColor = EditorResources.GetStyle("game-object-tree-view-scene-visibility") @@ -50,8 +62,6 @@ public class IconState public static readonly Color selectedNoFocusBackgroundColor = EditorResources.GetStyle("game-object-tree-view-scene-visibility") .GetColor("-unity-object-selected-no-focus-color"); - public static readonly GUIContent iconSceneHovered = EditorGUIUtility.TrIconContent("scenevis_scene_hover"); - public static readonly GUIStyle sceneVisibilityStyle = "SceneVisibility"; public static Color GetItemBackgroundColor(bool isHovered, bool isSelected, bool isFocused) @@ -77,7 +87,7 @@ public static Color GetItemBackgroundColor(bool isHovered, bool isSelected, bool private static float k_sceneHeaderOverflow => GameObjectTreeViewGUI.GameObjectStyles.sceneHeaderBg.fixedHeight + 2*GameObjectTreeViewGUI.GameObjectStyles.sceneHeaderWidth - EditorGUIUtility.singleLineHeight; private static bool m_PrevItemWasScene; - public const float utilityBarWidth = k_VisibilityIconPadding * 2 + k_IconWidth; + public const float utilityBarWidth = k_VisibilityIconPadding * 3 + k_IconWidth * 2; public static void DrawBackground(Rect rect) { @@ -97,9 +107,15 @@ public static void DoItemGUI(Rect rect, GameObjectTreeViewItem goItem, bool isSe isHovered = isHovered && !isDragging; bool isIconHovered = !isDragging && iconRect.Contains(Event.current.mousePosition); + Rect icon2Rect = rect; + icon2Rect.xMin += 2 * k_VisibilityIconPadding + k_IconWidth; + icon2Rect.width = k_IconWidth; + bool isIcon2Hovered = !isDragging && icon2Rect.Contains(Event.current.mousePosition); + if (isHovered) { GUIView.current.MarkHotRegion(GUIClip.UnclipToWindow(iconRect)); + GUIView.current.MarkHotRegion(GUIClip.UnclipToWindow(icon2Rect)); } GameObject gameObject = goItem.objectPPTR as GameObject; @@ -111,7 +127,9 @@ public static void DoItemGUI(Rect rect, GameObjectTreeViewItem goItem, bool isSe rect.yMin += k_sceneHeaderOverflow; DrawItemBackground(rect, false, isSelected, isHovered, isFocused); - DrawGameObjectItem(iconRect, gameObject, isHovered, isIconHovered); + DrawGameObjectItemVisibility(iconRect, gameObject, isHovered, isIconHovered); + DrawGameObjectItemPicking(icon2Rect, gameObject, isHovered, isIcon2Hovered); + m_PrevItemWasScene = false; } else @@ -120,7 +138,8 @@ public static void DoItemGUI(Rect rect, GameObjectTreeViewItem goItem, bool isSe if (scene.IsValid()) { DrawItemBackground(rect, true, isSelected, isHovered, isFocused); - DrawSceneItem(iconRect, scene, isHovered, isIconHovered); + DrawSceneItemVisibility(iconRect, scene, isHovered, isIconHovered); + DrawSceneItemPicking(icon2Rect, scene, isHovered, isIcon2Hovered); m_PrevItemWasScene = true; } } @@ -151,7 +170,7 @@ private static void DrawItemBackground(Rect rect, bool isScene, bool isSelected, } } - private static void DrawGameObjectItem(Rect rect, GameObject gameObject, bool isItemHovered, bool isIconHovered) + private static void DrawGameObjectItemVisibility(Rect rect, GameObject gameObject, bool isItemHovered, bool isIconHovered) { var isHidden = SceneVisibilityManager.instance.IsHidden(gameObject); bool shouldDisplayIcon = isItemHovered || isHidden; @@ -179,18 +198,46 @@ private static void DrawGameObjectItem(Rect rect, GameObject gameObject, bool is } } - private static void DrawSceneItem(Rect rect, Scene scene, bool isItemHovered, bool isIconHovered) + private static void DrawGameObjectItemPicking(Rect rect, GameObject gameObject, bool isItemHovered, bool isIconHovered) { - var state = SceneVisibilityManager.instance.GetSceneState(scene); + var isPickingDisabled = SceneVisibilityManager.instance.IsPickingDisabled(gameObject); + bool shouldDisplayIcon = isItemHovered || isPickingDisabled; + Styles.IconState iconState = isIconHovered ? Styles.iconHovered : Styles.iconNormal; + + GUIContent icon; + if (isPickingDisabled) + { + icon = gameObject.transform.childCount == 0 || SceneVisibilityManager.instance.IsPickingDisabledOnAllDescendants(gameObject) + ? iconState.pickingDisabledAll : iconState.pickingDisabledMixed; + } + else if (!SceneVisibilityManager.instance.IsPickingEnabledOnAllDescendants(gameObject)) + { + icon = iconState.pickingEnabledMixed; + shouldDisplayIcon = true; + } + else + { + icon = iconState.pickingEnabledAll; + } + + if (shouldDisplayIcon && GUI.Button(rect, icon, Styles.sceneVisibilityStyle)) + { + SceneVisibilityManager.instance.TogglePicking(gameObject, !Event.current.alt); + } + } + + private static void DrawSceneItemVisibility(Rect rect, Scene scene, bool isItemHovered, bool isIconHovered) + { + var state = SceneVisibilityManager.instance.GetSceneVisibilityState(scene); bool shouldDisplayIcon = true; Styles.IconState iconState = isIconHovered ? Styles.iconHovered : Styles.iconNormal; GUIContent icon; - if (state == SceneVisibilityManager.SceneState.AllHidden) + if (state == SceneVisibilityManager.SceneVisState.AllHidden) { icon = iconState.hiddenAll; } - else if (state == SceneVisibilityManager.SceneState.Mixed) + else if (state == SceneVisibilityManager.SceneVisState.Mixed) { icon = iconState.visibleMixed; } @@ -206,5 +253,41 @@ private static void DrawSceneItem(Rect rect, Scene scene, bool isItemHovered, bo SceneVisibilityManager.instance.ToggleScene(scene, state); } } + + private static void DrawSceneItemPicking(Rect rect, Scene scene, bool isItemHovered, bool isIconHovered) + { + var state = SceneVisibilityManager.instance.GetScenePickingState(scene); + bool shouldDisplayIcon = true; + Styles.IconState iconState = isIconHovered ? Styles.iconHovered : Styles.iconNormal; + + GUIContent icon; + var enablePicking = false; + if (state == SceneVisibilityManager.ScenePickingState.PickingDisabledAll) + { + icon = iconState.pickingDisabledAll; + enablePicking = true; + } + else if (state == SceneVisibilityManager.ScenePickingState.Mixed) + { + icon = iconState.pickingEnabledMixed; + } + else + { + icon = iconState.pickingEnabledAll; + shouldDisplayIcon = isItemHovered; + } + + if (shouldDisplayIcon && GUI.Button(rect, icon, Styles.sceneVisibilityStyle)) + { + if (enablePicking) + { + SceneVisibilityManager.instance.EnablePicking(scene); + } + else + { + SceneVisibilityManager.instance.DisablePicking(scene); + } + } + } } } diff --git a/Editor/Mono/SceneVisibilityManager.cs b/Editor/Mono/SceneVisibilityManager.cs index db8848f4a0..68f3d9487b 100644 --- a/Editor/Mono/SceneVisibilityManager.cs +++ b/Editor/Mono/SceneVisibilityManager.cs @@ -37,14 +37,22 @@ public bool active public static event Action visibilityChanged; + public static event Action pickingChanged; + internal static event Action currentStageIsolated; private readonly static List m_RootBuffer = new List(); internal bool enableSceneVisibility { - get { return SceneVisibilityState.active; } - set { SceneVisibilityState.active = value; } + get { return SceneVisibilityState.visibilityActive; } + set { SceneVisibilityState.visibilityActive = value; } + } + + internal bool enableScenePicking + { + get { return SceneVisibilityState.pickingActive; } + set { SceneVisibilityState.pickingActive = value; } } [InitializeOnLoadMethod] @@ -70,14 +78,14 @@ private static void Initialize() private static void InternalStructureChanged() { instance.VisibilityChanged(); + instance.PickableContentChanged(); } private static void EditorSceneManagerOnSceneOpened(Scene scene, OpenSceneMode mode) { if (mode == OpenSceneMode.Single) { - //force out of isolation when loading single - SceneVisibilityState.mainStageIsolated = false; + SceneVisibilityState.isolation = false; } if (mode == OpenSceneMode.Additive) { @@ -85,15 +93,15 @@ private static void EditorSceneManagerOnSceneOpened(Scene scene, OpenSceneMode m if (!StageNavigationManager.instance.currentItem.isPrefabStage) { Undo.ClearUndo(SceneVisibilityState.GetInstance()); - if (SceneVisibilityState.mainStageIsolated) - SceneVisibilityState.SetSceneIsolation(scene, true); } } instance.VisibilityChanged(); + instance.PickableContentChanged(); } private static void StageNavigationManagerOnStageChanging(StageNavigationItem oldItem, StageNavigationItem newItem) { + RevertIsolationCurrentStage(); if (!newItem.isMainStage && newItem.prefabStage != null) { SceneVisibilityState.SetPrefabStageScene(newItem.prefabStage.scene); @@ -102,10 +110,6 @@ private static void StageNavigationManagerOnStageChanging(StageNavigationItem ol { SceneVisibilityState.SetPrefabStageScene(default(Scene)); } - if (!oldItem.isMainStage) - { - SceneVisibilityState.prefabStageIsolated = false; - } } private static void EditorApplicationPlayModeStateChanged(PlayModeStateChange state) @@ -115,6 +119,7 @@ private static void EditorApplicationPlayModeStateChanged(PlayModeStateChange st SceneVisibilityState.GeneratePersistentDataForAllLoadedScenes(); } instance.VisibilityChanged(); + instance.PickableContentChanged(); } private static void EditorSceneManagerOnSceneSaved(Scene scene) @@ -148,6 +153,7 @@ private static void EditorSceneManagerOnNewSceneCreated(Scene scene, NewSceneSet //need to clear scene on new scene since all new scenes use the same GUID SceneVisibilityState.ClearScene(scene); instance.VisibilityChanged(); + instance.PickableContentChanged(); } private static void UndoRedoPerformed() @@ -179,6 +185,30 @@ private void HideAllNoUndo() } } + public void DisableAllPicking() + { + Undo.RecordObject(SceneVisibilityState.GetInstance(), "Disable All Picking"); + DisableAllPickingNoUndo(); + PickableContentChanged(); + } + + private void DisableAllPickingNoUndo() + { + if (StageNavigationManager.instance.currentItem.isPrefabStage) + { + var scene = StageNavigationManager.instance.GetCurrentPrefabStage().scene; + SceneVisibilityState.EnablePicking(StageNavigationManager.instance.GetCurrentPrefabStage().scene); + SceneVisibilityState.DisablePicking(scene); + } + else + { + for (int i = 0; i < SceneManager.sceneCount; i++) + { + DisablePicking(SceneManager.GetSceneAt(i), false); + } + } + } + public void Show(GameObject gameObject, bool includeDescendants) { Undo.RecordObject(SceneVisibilityState.GetInstance(), "Show GameObject"); @@ -188,11 +218,25 @@ public void Show(GameObject gameObject, bool includeDescendants) public void Hide(GameObject gameObject, bool includeDescendants) { - Undo.RecordObject(SceneVisibilityState.GetInstance(), "Set GameObject Hidden"); + Undo.RecordObject(SceneVisibilityState.GetInstance(), "Hide GameObject"); SceneVisibilityState.SetGameObjectHidden(gameObject, true, includeDescendants); VisibilityChanged(); } + public void DisablePicking(GameObject gameObject, bool includeDescendants) + { + Undo.RecordObject(SceneVisibilityState.GetInstance(), "Disable Picking GameObject"); + SceneVisibilityState.SetGameObjectPickingDisabled(gameObject, true, includeDescendants); + PickableContentChanged(); + } + + public void EnablePicking(GameObject gameObject, bool includeDescendants) + { + Undo.RecordObject(SceneVisibilityState.GetInstance(), "Enable Picking GameObject"); + SceneVisibilityState.SetGameObjectPickingDisabled(gameObject, false, includeDescendants); + PickableContentChanged(); + } + [Shortcut("Scene Visibility/Show All")] internal static void ShowAllShortcut() { @@ -216,6 +260,23 @@ public void ShowAll() VisibilityChanged(); } + public void EnableAllPicking() + { + Undo.RecordObject(SceneVisibilityState.GetInstance(), "Enable All Picking"); + if (StageNavigationManager.instance.currentItem.isPrefabStage) + { + SceneVisibilityState.EnablePicking(StageNavigationManager.instance.GetCurrentPrefabStage().scene); + } + else + { + for (int i = 0; i < SceneManager.sceneCount; i++) + { + EnablePicking(SceneManager.GetSceneAt(i), false); + } + } + PickableContentChanged(); + } + private void Show(Scene scene, bool sendContentChangedEvent) { if (!scene.IsValid()) @@ -229,6 +290,19 @@ private void Show(Scene scene, bool sendContentChangedEvent) } } + private void EnablePicking(Scene scene, bool sendContentChangedEvent) + { + if (!scene.IsValid()) + return; + + SceneVisibilityState.EnablePicking(scene); + + if (sendContentChangedEvent) + { + PickableContentChanged(); + } + } + public void Show(Scene scene) { if (!scene.IsValid()) @@ -238,6 +312,15 @@ public void Show(Scene scene) Show(scene, true); } + public void EnablePicking(Scene scene) + { + if (!scene.IsValid()) + return; + + Undo.RecordObject(SceneVisibilityState.GetInstance(), "Enable Picking Scene"); + EnablePicking(scene, true); + } + private void Hide(Scene scene, bool sendContentChangedEvent) { if (!scene.IsValid()) @@ -252,6 +335,20 @@ private void Hide(Scene scene, bool sendContentChangedEvent) } } + internal void DisablePicking(Scene scene, bool sendContentChangedEvent) + { + if (!scene.IsValid()) + return; + + SceneVisibilityState.EnablePicking(scene); + SceneVisibilityState.SetGameObjectsPickingDisabled(scene.GetRootGameObjects(), true, true); + + if (sendContentChangedEvent) + { + PickableContentChanged(); + } + } + public void Hide(Scene scene) { if (!scene.IsValid()) @@ -261,6 +358,15 @@ public void Hide(Scene scene) Hide(scene, true); } + public void DisablePicking(Scene scene) + { + if (!scene.IsValid()) + return; + + Undo.RecordObject(SceneVisibilityState.GetInstance(), "Disable Picking Scene"); + DisablePicking(scene, true); + } + public bool IsHidden(GameObject gameObject, bool includeDescendants = false) { if (includeDescendants) @@ -269,6 +375,21 @@ public bool IsHidden(GameObject gameObject, bool includeDescendants = false) return SceneVisibilityState.IsGameObjectHidden(gameObject); } + public bool IsPickingDisabled(GameObject gameObject, bool includeDescendants = false) + { + if (includeDescendants) + return SceneVisibilityState.IsHierarchyPickingDisabled(gameObject); + else + return SceneVisibilityState.IsGameObjectPickingDisabled(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) @@ -277,6 +398,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; } @@ -284,25 +408,64 @@ public bool AreAllDescendantsHidden(Scene scene) return true; } + public bool IsPickingDisabledOnAllDescendants(Scene scene) + { + if (scene.rootCount == 0) + return false; + + scene.GetRootGameObjects(m_RootBuffer); + foreach (GameObject root in m_RootBuffer) + { + if (IsIgnoredBySceneVisibility(root)) + continue; + + if (!SceneVisibilityState.IsHierarchyPickingDisabled(root)) + return false; + } + + return true; + } + public bool AreAnyDescendantsHidden(Scene scene) { return SceneVisibilityState.HasHiddenGameObjects(scene); } - internal enum SceneState + public bool IsPickingDisabledOnAnyDescendant(Scene scene) + { + return SceneVisibilityState.ContainsGameObjectsWithPickingDisabled(scene); + } + + internal enum SceneVisState { AllHidden, AllVisible, Mixed } - internal SceneState GetSceneState(Scene scene) + internal enum ScenePickingState + { + PickingDisabledAll, + PickingEnabledAll, + Mixed + } + + internal SceneVisState GetSceneVisibilityState(Scene scene) { if (AreAllDescendantsHidden(scene)) - return SceneState.AllHidden; + return SceneVisState.AllHidden; if (AreAnyDescendantsHidden(scene)) - return SceneState.Mixed; - return SceneState.AllVisible; + return SceneVisState.Mixed; + return SceneVisState.AllVisible; + } + + internal ScenePickingState GetScenePickingState(Scene scene) + { + if (IsPickingDisabledOnAllDescendants(scene)) + return ScenePickingState.PickingDisabledAll; + if (IsPickingDisabledOnAnyDescendant(scene)) + return ScenePickingState.Mixed; + return ScenePickingState.PickingEnabledAll; } public void Show(GameObject[] gameObjects, bool includeDescendants) @@ -319,6 +482,20 @@ public void Hide(GameObject[] gameObjects, bool includeDescendants) VisibilityChanged(); } + public void DisablePicking(GameObject[] gameObjects, bool includeDescendants) + { + Undo.RecordObject(SceneVisibilityState.GetInstance(), "Disable Picking GameObjects"); + SceneVisibilityState.SetGameObjectsPickingDisabled(gameObjects, true, includeDescendants); + PickableContentChanged(); + } + + public void EnablePicking(GameObject[] gameObjects, bool includeDescendants) + { + Undo.RecordObject(SceneVisibilityState.GetInstance(), "Enable Picking GameObjects"); + SceneVisibilityState.SetGameObjectsPickingDisabled(gameObjects, false, includeDescendants); + PickableContentChanged(); + } + public void Isolate(GameObject gameObject, bool includeDescendants) { Undo.RecordObject(SceneVisibilityState.GetInstance(), "Isolate GameObject"); @@ -344,6 +521,11 @@ private void VisibilityChanged() visibilityChanged?.Invoke(); } + private void PickableContentChanged() + { + pickingChanged?.Invoke(); + } + public void ToggleVisibility(GameObject gameObject, bool includeDescendants) { Undo.RecordObject(SceneVisibilityState.GetInstance(), "Toggle Visibility"); @@ -351,6 +533,13 @@ public void ToggleVisibility(GameObject gameObject, bool includeDescendants) VisibilityChanged(); } + public void TogglePicking(GameObject gameObject, bool includeDescendants) + { + Undo.RecordObject(SceneVisibilityState.GetInstance(), "Toggle Picking"); + SceneVisibilityState.SetGameObjectPickingDisabled(gameObject, !SceneVisibilityState.IsGameObjectPickingDisabled(gameObject), includeDescendants); + PickableContentChanged(); + } + public bool AreAllDescendantsHidden(GameObject gameObject) { return SceneVisibilityState.AreAllChildrenHidden(gameObject); @@ -361,6 +550,39 @@ public bool AreAllDescendantsVisible(GameObject gameObject) return SceneVisibilityState.AreAllChildrenVisible(gameObject); } + public bool IsPickingDisabledOnAllDescendants(GameObject gameObject) + { + return SceneVisibilityState.IsPickingDisabledOnAllChildren(gameObject); + } + + public bool IsPickingEnabledOnAllDescendants(GameObject gameObject) + { + return SceneVisibilityState.IsPickingEnabledOnAllChildren(gameObject); + } + + public bool IsCurrentStageIsolated() + { + return SceneVisibilityState.isolation; + } + + private void IsolateCurrentStage() + { + SceneVisibilityState.isolation = true; + currentStageIsolated?.Invoke(); + } + + public void ExitIsolation() + { + Undo.RecordObject(SceneVisibilityState.GetInstance(), "Exit Isolation"); + RevertIsolationCurrentStage(); + VisibilityChanged(); + } + + private static void RevertIsolationCurrentStage() + { + SceneVisibilityState.isolation = false; + } + //SHORTCUTS [Shortcut("Scene Visibility/Toggle Selection Visibility")] private static void ToggleSelectionVisibility() @@ -398,69 +620,51 @@ private static void ToggleSelectionAndDescendantsVisibility() shouldHide = false; } - Undo.RecordObject(SceneVisibilityState.GetInstance(), "Toggle Visibility And Children"); + Undo.RecordObject(SceneVisibilityState.GetInstance(), "Toggle Selection And Descendants Visibility"); SceneVisibilityState.SetGameObjectsHidden(Selection.gameObjects, shouldHide, true); instance.VisibilityChanged(); } } - public bool IsCurrentStageIsolated() - { - return StageNavigationManager.instance.currentItem.isPrefabStage ? SceneVisibilityState.prefabStageIsolated : SceneVisibilityState.mainStageIsolated; - } - - private void IsolateCurrentStage() + [Shortcut("Scene Picking/Toggle Picking On Selection And Descendants", typeof(ShortcutContext), KeyCode.L)] + private static void ToggleSelectionAndDescendantsPicking() { - if (StageNavigationManager.instance.currentItem.isPrefabStage) - { - SceneVisibilityState.prefabStageIsolated = true; - SceneVisibilityState.SetSceneIsolation(StageNavigationManager.instance.GetCurrentPrefabStage().scene, true); - } - else + if (Selection.gameObjects.Length > 0) { - SceneVisibilityState.mainStageIsolated = true; - for (int i = 0; i < SceneManager.sceneCount; i++) + bool shouldDisablePicking = true; + foreach (var gameObject in Selection.gameObjects) { - var scene = SceneManager.GetSceneAt(i); - SceneVisibilityState.SetSceneIsolation(scene, true); - } - } - - currentStageIsolated?.Invoke(); - } - - public void ExitIsolation() - { - Undo.RecordObject(SceneVisibilityState.GetInstance(), "Exit Isolation"); + if (!instance.IsPickingDisabled(gameObject)) + { + break; + } - if (IsCurrentStageIsolated()) //already isolated - { - RevertIsolationCurrentStage(); - VisibilityChanged(); + shouldDisablePicking = false; + } + Undo.RecordObject(SceneVisibilityState.GetInstance(), "Toggle Selection And Descendants Picking"); + SceneVisibilityState.SetGameObjectsPickingDisabled(Selection.gameObjects, shouldDisablePicking, true); + instance.VisibilityChanged(); } } - private static void RevertIsolationCurrentStage() + [Shortcut("Scene Picking/Toggle Picking On Selection")] + internal static void ToggleSelectionPickable() { - if (StageNavigationManager.instance.currentItem.isPrefabStage) - { - SceneVisibilityState.prefabStageIsolated = false; - SceneVisibilityState.SetSceneIsolation(StageNavigationManager.instance.GetCurrentPrefabStage().scene, false); - } - else + if (Selection.gameObjects.Length > 0) { - SceneVisibilityState.mainStageIsolated = false; - for (int i = 0; i < SceneManager.sceneCount; i++) + bool shouldHide = true; + foreach (var gameObject in Selection.gameObjects) { - var scene = SceneManager.GetSceneAt(i); - SceneVisibilityState.SetSceneIsolation(scene, false); - } - } + if (!instance.IsPickingDisabled(gameObject)) + { + break; + } - //If no more isolation, ensure that every scenes in DB has it's isolation cleared (including unloaded scenes) - if (!SceneVisibilityState.prefabStageIsolated && !SceneVisibilityState.mainStageIsolated) - { - SceneVisibilityState.ClearIsolation(); + shouldHide = false; + } + Undo.RecordObject(SceneVisibilityState.GetInstance(), "Toggle Selection Pickable"); + SceneVisibilityState.SetGameObjectsPickingDisabled(Selection.gameObjects, shouldHide, false); + instance.PickableContentChanged(); } } @@ -471,7 +675,7 @@ private static void ExitIsolationShortcut() } [Shortcut("Scene Visibility/Toggle Isolation On Selection And Descendants", typeof(ShortcutContext), KeyCode.H, ShortcutModifiers.Shift)] - static void ToggleIsolateSelectionAndDescendantsShortcut() + private static void ToggleIsolateSelectionAndDescendantsShortcut() { instance.ToggleIsolateSelectionAndDescendants(); } @@ -500,7 +704,7 @@ internal void ToggleIsolateSelectionAndDescendants() } [Shortcut("Scene Visibility/Toggle Isolation on Selection")] - static void ToggleIsolateSelectionShortcut() + private static void ToggleIsolateSelectionShortcut() { instance.ToggleIsolateSelection(); } @@ -528,9 +732,9 @@ internal void ToggleIsolateSelection() } } - internal void ToggleScene(Scene scene, SceneState state) + internal void ToggleScene(Scene scene, SceneVisState visibilityState) { - if (state == SceneState.AllVisible) + if (visibilityState == SceneVisState.AllVisible || visibilityState == SceneVisState.Mixed) { Hide(scene); } diff --git a/Editor/Mono/ScriptEditorUtility.cs b/Editor/Mono/ScriptEditorUtility.cs index 3816412c30..11e4763727 100644 --- a/Editor/Mono/ScriptEditorUtility.cs +++ b/Editor/Mono/ScriptEditorUtility.cs @@ -18,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 { @@ -51,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; @@ -98,6 +90,36 @@ public static void SetExternalScriptEditor(string 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 + // 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. + if (Application.platform == RuntimePlatform.OSXEditor) + return "kScriptEditorArgs_" + path; + + return "kScriptEditorArgs" + path; + } + + static string GetDefaultStringEditorArgs() + { + // On OSX there is a built-in mechanism for opening files in apps. + // We use this mechanism when the external script editor args are not set. + // Which was the only support behaviour before Unity 5.5. We therefor + // default to this behavior. + // If the script editor args are set, we only launch the script editor with args + // specified and do not use the built-in mechanism for opening script files. + if (Application.platform == RuntimePlatform.OSXEditor) + return ""; + + return "\"$(File)\""; + } + public static string GetExternalScriptEditorArgs() { throw new NotSupportedException("This functionality has been moved to the IExternalCodeEditor packages"); diff --git a/Editor/Mono/ScriptableSingleton.cs b/Editor/Mono/ScriptableSingleton.cs index 84c133216e..0330c294c1 100644 --- a/Editor/Mono/ScriptableSingleton.cs +++ b/Editor/Mono/ScriptableSingleton.cs @@ -17,7 +17,7 @@ namespace UnityEditor [AttributeUsage(AttributeTargets.Class)] internal class FilePathAttribute : Attribute { - public enum Location { PreferencesFolder, ProjectFolder } + public enum Location { PreferencesFolder, ProjectFolder, AppDataFolder } private string filePath; private string relativePath; @@ -62,6 +62,8 @@ static string GetFilePath(string relativePath, Location location) if (location == Location.PreferencesFolder) return InternalEditorUtility.unityPreferencesFolder + "/" + relativePath; + else if (location == Location.AppDataFolder) + return InternalEditorUtility.userAppDataFolder + "/" + relativePath; else //location == Location.ProjectFolder return relativePath; } diff --git a/Editor/Mono/Scripting/Compilers/CSharpLanguage.cs b/Editor/Mono/Scripting/Compilers/CSharpLanguage.cs index 7cd9dc9b92..a595538132 100644 --- a/Editor/Mono/Scripting/Compilers/CSharpLanguage.cs +++ b/Editor/Mono/Scripting/Compilers/CSharpLanguage.cs @@ -62,48 +62,74 @@ static string[] GetSystemReferenceDirectories(ApiCompatibilityLevel apiCompatibi return MonoLibraryHelpers.GetSystemReferenceDirectories(apiCompatibilityLevel); } - public string GetNamespaceNewRuntime(string filePath, string[] definesSymbols, string[] rspDefines) + public string GetNamespaceNewRuntime(string filePath, string definedSymbols, string[] defines) { - var uniqueSymbols = definesSymbols; - if (rspDefines != null && rspDefines.Any()) - { - uniqueSymbols = definesSymbols.Union(rspDefines).Distinct().ToArray(); - } - + var definedSymbolSplit = definedSymbols.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + var uniqueSymbols = defines.Union(definedSymbolSplit).Distinct().ToArray(); return CSharpNamespaceParser.GetNamespace( ReadAndConverteNewLines(filePath).ReadToEnd(), Path.GetFileNameWithoutExtension(filePath), uniqueSymbols); } - public override string GetNamespace(string filePath, string definedSymbols) + public string GetNamespaceOldRuntime(string filePath, string definedSymbols, string[] defines) { - var targetAssemblyFromPath = EditorCompilationInterface.Instance.GetTargetAssemblyFromPath(filePath); - var definedSymbolsSplit = definedSymbols.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - - string[] fullListOfDefines = new string[definedSymbolsSplit.Length + (targetAssemblyFromPath?.Defines?.Length ?? 0)]; - Array.Copy(definedSymbolsSplit, fullListOfDefines, definedSymbolsSplit.Length); - - if (targetAssemblyFromPath?.Defines != null) + var definedSymbolSplit = definedSymbols.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + var uniqueSymbols = defines.Union(definedSymbolSplit).Distinct().ToArray(); + using (var parser = ParserFactory.CreateParser(ICSharpCode.NRefactory.SupportedLanguage.CSharp, ReadAndConverteNewLines(filePath))) { - Array.Copy(targetAssemblyFromPath.Defines, 0, fullListOfDefines, definedSymbolsSplit.Length, targetAssemblyFromPath.Defines.Length); + foreach (var symbol in uniqueSymbols) + { + parser.Lexer.ConditionalCompilationSymbols.Add(symbol, string.Empty); + } + + parser.Lexer.EvaluateConditionalCompilation = true; + parser.Parse(); + try + { + var visitor = new NamespaceVisitor(); + var data = new VisitorData { TargetClassName = Path.GetFileNameWithoutExtension(filePath) }; + parser.CompilationUnit.AcceptVisitor(visitor, data); + return string.IsNullOrEmpty(data.DiscoveredNamespace) ? string.Empty : data.DiscoveredNamespace; + } + catch + { + // Don't care; all we want is the namespace + } } + return string.Empty; + } - var rspFile = targetAssemblyFromPath?.GetResponseFiles()?.FirstOrDefault(); - ApiCompatibilityLevel compatibilityLevel = ApiCompatibilityLevel.NET_4_6; - - string[] rspDefines = null; - if (!string.IsNullOrEmpty(rspFile)) - { - rspDefines = ScriptCompilerBase.ParseResponseFileFromFile( - rspFile, - Application.dataPath, - GetSystemReferenceDirectories(compatibilityLevel)).Defines; - } + public override void GetClassAndNamespace(string filePath, string definedSymbols, + out string outClassName, out string outNamespace) + { + var responseFilePath = Path.Combine("Assets", MicrosoftCSharpCompiler.ResponseFilename); + var responseFileData = ScriptCompilerBase.ParseResponseFileFromFile( + responseFilePath, + Directory.GetParent(Application.dataPath).FullName, + GetSystemReferenceDirectories(ApiCompatibilityLevel.NET_4_6)); + + var definedSymbolSplit = definedSymbols.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + var uniqueSymbols = responseFileData.Defines.Union(definedSymbolSplit).Distinct().ToArray(); + CSharpNamespaceParser.GetClassAndNamespace(ReadAndConverteNewLines(filePath).ReadToEnd(), + Path.GetFileNameWithoutExtension(filePath), out outClassName, out outNamespace, uniqueSymbols); + } - return GetNamespaceNewRuntime(filePath, fullListOfDefines, rspDefines); + public override string GetNamespace(string filePath, string definedSymbols) + { + var responseFilePath = Path.Combine("Assets", MicrosoftCSharpCompiler.ResponseFilename); + var responseFileData = ScriptCompilerBase.ParseResponseFileFromFile( + responseFilePath, + Directory.GetParent(Application.dataPath).FullName, + GetSystemReferenceDirectories(ApiCompatibilityLevel.NET_4_6)); + return GetNamespaceNewRuntime(filePath, definedSymbols, responseFileData.Defines); } + // TODO: Revisit this code and switch to version 5.5.1 (or Roslyn if possible) when Editor switches to newer runtime version (on going work expected + // to finish around 2017.2 or 2017.3 release. + // + // This is a workaround for a bug in version 3.2.1 of NRefactory in which it fails to parse sources with a combination of LF / #if / #else + // Version 5.5.1 is confirmed to not have this bug but we can't use it since it requires a newer runtime/c# version; static StringReader ReadAndConverteNewLines(string filePath) { var text = File.ReadAllText(filePath); @@ -113,5 +139,47 @@ static StringReader ReadAndConverteNewLines(string filePath) return new StringReader(text); } + + class VisitorData + { + public VisitorData() + { + CurrentNamespaces = new Stack(); + } + + public string TargetClassName; + public Stack CurrentNamespaces; + public string DiscoveredNamespace; + } + class NamespaceVisitor : AbstractAstVisitor + { + public override object VisitNamespaceDeclaration(ICSharpCode.NRefactory.Ast.NamespaceDeclaration namespaceDeclaration, object data) + { + var visitorData = (VisitorData)data; + visitorData.CurrentNamespaces.Push(namespaceDeclaration.Name); + // Visit children (E.g. TypeDcelarion objects) + namespaceDeclaration.AcceptChildren(this, visitorData); + visitorData.CurrentNamespaces.Pop(); + return null; + } + + public override object VisitTypeDeclaration(ICSharpCode.NRefactory.Ast.TypeDeclaration typeDeclaration, object data) + { + var visitorData = (VisitorData)data; + if (typeDeclaration.Name == visitorData.TargetClassName) + { + var fullNamespace = string.Empty; + foreach (var ns in visitorData.CurrentNamespaces) + { + if (fullNamespace == string.Empty) + fullNamespace = ns; + else + fullNamespace = ns + "." + fullNamespace; + } + visitorData.DiscoveredNamespace = fullNamespace; + } + return null; + } + } } } diff --git a/Editor/Mono/Scripting/Compilers/ScriptCompilerBase.cs b/Editor/Mono/Scripting/Compilers/ScriptCompilerBase.cs index 24027f9cfe..6402839462 100644 --- a/Editor/Mono/Scripting/Compilers/ScriptCompilerBase.cs +++ b/Editor/Mono/Scripting/Compilers/ScriptCompilerBase.cs @@ -93,8 +93,8 @@ internal static void AddResponseFileToArguments(List arguments, string r } arguments.AddRange(responseFileData.Defines.Distinct().Select(define => "/define:" + define)); - arguments.AddRange(responseFileData.FullPathReferences.Select(reference => - "/reference:" + PrepareFileName(reference))); + arguments.AddRange(responseFileData.References.Select(reference => + $"/reference:{GetAliasString(reference)}{PrepareFileName(reference.FullPathReference)}")); if (responseFileData.Unsafe) { arguments.Add("/unsafe"); @@ -102,6 +102,16 @@ internal static void AddResponseFileToArguments(List arguments, string r arguments.AddRange(responseFileData.OtherArguments); } + private static string GetAliasString(ResponseFileReference responseFileReference) + { + if (string.IsNullOrEmpty(responseFileReference.Alias)) + { + return string.Empty; + } + + return $"{responseFileReference.Alias}="; + } + public static ResponseFileData ParseResponseFileFromFile( string responseFilePath, string projectDirectory, @@ -129,6 +139,7 @@ public static ResponseFileData ParseResponseFileFromFile( { Defines = new string[0], FullPathReferences = new string[0], + References = new ResponseFileReference[0], Unsafe = false, Errors = new string[0], OtherArguments = new string[0], @@ -252,7 +263,7 @@ static ResponseFileData ParseResponseFileText( var responseArguments = new List(); var defines = new List(); - var references = new List(); + var references = new List(); bool unsafeDefined = false; var errors = new List(); @@ -303,6 +314,7 @@ static ResponseFileData ParseResponseFileText( int index = reference.IndexOf('='); var responseReference = index > -1 ? reference.Substring(index + 1) : reference; + var alias = index > -1 ? reference.Substring(0, index) : string.Empty; var fullPathReference = responseReference; bool isRooted = Path.IsPathRooted(responseReference); @@ -335,7 +347,11 @@ static ResponseFileData ParseResponseFileText( } responseReference = fullPathReference.Replace('\\', '/'); - references.Add(responseReference); + references.Add(new ResponseFileReference + { + FullPathReference = responseReference, + Alias = alias, + }); } break; @@ -361,7 +377,8 @@ static ResponseFileData ParseResponseFileText( var responseFileData = new ResponseFileData { Defines = defines.ToArray(), - FullPathReferences = references.ToArray(), + FullPathReferences = references.Select(x => x.FullPathReference).ToArray(), + References = references.ToArray(), Unsafe = unsafeDefined, Errors = errors.ToArray(), OtherArguments = responseArguments.ToArray(), diff --git a/Editor/Mono/Scripting/Compilers/SupportedLanguage.cs b/Editor/Mono/Scripting/Compilers/SupportedLanguage.cs index 93d55a886c..6a503b76c7 100644 --- a/Editor/Mono/Scripting/Compilers/SupportedLanguage.cs +++ b/Editor/Mono/Scripting/Compilers/SupportedLanguage.cs @@ -17,6 +17,14 @@ public virtual ResponseFileProvider CreateResponseFileProvider() public abstract string GetLanguageName(); public abstract ScriptCompilerBase CreateCompiler(ScriptAssembly scriptAssembly, EditorScriptCompilationOptions options, string tempOutputDirectory); + + public virtual void GetClassAndNamespace(string fileName, string definedSymbols, out string outClassName, + out string outNamespace) + { + outClassName = string.Empty; + outNamespace = string.Empty; + } + public virtual string GetNamespace(string fileName, string definedSymbols) { return string.Empty; diff --git a/Editor/Mono/Scripting/ScriptCompilation/AutoReferencedPackageAssemblies.cs b/Editor/Mono/Scripting/ScriptCompilation/AutoReferencedPackageAssemblies.cs index 1a17233349..6eab9084a8 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/AutoReferencedPackageAssemblies.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/AutoReferencedPackageAssemblies.cs @@ -38,7 +38,7 @@ static AutoReferencedPackageAssemblies() ignoreAssemblies.UnionWith(editorAssemblyNames); } - public static void AddReferences(Dictionary customTargetAssemblies, EditorScriptCompilationOptions options) + public static void AddReferences(Dictionary customTargetAssemblies, EditorScriptCompilationOptions options, Func shouldAdd) { if (customTargetAssemblies == null || customTargetAssemblies.Count() == 0) return; @@ -74,12 +74,17 @@ public static void AddReferences(Dictionary customTarget { var assembly = entry.Value; + if (!shouldAdd?.Invoke(assembly) ?? false) + { + continue; + } + // Do not add additional references to any of the - // automaticly referenced or ignored assemblies + // automatically referenced or ignored assemblies if (ignoreAssemblies.Contains(assembly.Filename)) continue; - // Add the automtic references. + // Add the automatic 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 97bdc44ea6..cd62c71ea0 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/CSharpNamespaceParser.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/CSharpNamespaceParser.cs @@ -34,9 +34,60 @@ internal static class CSharpNamespaceParser static readonly Regex k_NewlineRegex = new Regex("\r\n?", RegexOptions.Compiled); static readonly Regex k_SingleQuote = new Regex(@"((? s_FoundTypes = new HashSet(); + + // Used for detecting warning in PureCSharpTests + public static Action s_LogWarningAction; + static CSharpNamespaceParser() + { + s_LogWarningAction = Debug.LogWarning; + } + + public static void GetClassAndNamespace(string sourceCode, string className, + out string outClassName, out string outNamespace, params string[] defines) + { + bool namespaceParsed = false; + outClassName = className; + outNamespace = string.Empty; + + // Check for authoring component and try to parse it as class name with namespace if present + var authoringComponentCodeIndex = sourceCode.IndexOf(k_GenerateAuthoringComponentAttribute, + StringComparison.Ordinal); + if (authoringComponentCodeIndex != -1) + { + string foundClassName = string.Empty; + var codeFromAttribute = sourceCode.Substring(authoringComponentCodeIndex); + var match = k_GenerateAuthoringComponentClassName.Match(codeFromAttribute); + if (match.Groups.Count <= 1) + s_LogWarningAction($"Code contains {k_GenerateAuthoringComponentAttribute} attributes but no valid following struct."); + else + { + foundClassName = match.Groups[1].Value; + outClassName = foundClassName + k_AuthoringComponentSuffix; + outNamespace = FindNamespace(sourceCode, foundClassName, true, defines); + namespaceParsed = true; + } + } + + // No authoring component attribute found, or we couldn't parse it, do normal namespace parsing + if (!namespaceParsed) + { + outClassName = className; + outNamespace = FindNamespace(sourceCode, className, false, defines); + } + } public static string GetNamespace(string sourceCode, string className, params string[] defines) + { + return FindNamespace(sourceCode, className, false, defines); + } + + static string FindNamespace(string sourceCode, string className, bool acceptStruct, params string[] defines) { s_ClassName = className; @@ -48,9 +99,8 @@ public static string GetNamespace(string sourceCode, string className, params st sourceCode = k_VerbatimStrings.Replace(sourceCode, ""); try { - sourceCode = RemoveUnusedDefines(sourceCode, defines.ToList()); - - return FindNamespaceForMono(className, sourceCode); + sourceCode = ReduceCodeAndCheckForNamespacesModification(sourceCode, className); + return FindClassAndNamespace(className, sourceCode, acceptStruct); } catch (Exception e) { @@ -58,14 +108,16 @@ public static string GetNamespace(string sourceCode, string className, params st } } - static string FindNamespaceForMono(string className, string source) + static string FindClassAndNamespace(string className, string source, bool acceptStruct = false) { + s_FoundTypes.Clear(); source = FixBraces(source); var split = source.Split(new[] { ' ', '\t', '\n' }, StringSplitOptions.RemoveEmptyEntries).ToList(); var parent = new Node { Name = "-1" }; var builder = new StringBuilder(source.Length); var buildingNode = false; var buildingClass = false; + var classAlreadyFoundInOtherNamespace = false; var level = 0; var resNamespace = ""; foreach (var token in split) @@ -94,6 +146,13 @@ static string FindNamespaceForMono(string className, string source) buildingClass = true; buildingNode = true; break; + case "struct": + if (acceptStruct) + { + buildingClass = true; + buildingNode = true; + } + break; case "namespace": buildingNode = true; break; @@ -104,7 +163,13 @@ static string FindNamespaceForMono(string className, string source) if (buildingClass && strippedClassname.Equals(className)) { buildingClass = false; - resNamespace = CollectNamespace(parent); + 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 { @@ -167,21 +232,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 && 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, string className) { 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 deeper than top level of directives + if (k_Namespace.IsMatch(s)) + { + if (stack.Count > 1) + namespaceModificationFound = true; + 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; } @@ -189,6 +286,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)); @@ -205,36 +303,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( + $"While looking for class {className} 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(); } diff --git a/Editor/Mono/Scripting/ScriptCompilation/CompilationPipeline.cs b/Editor/Mono/Scripting/ScriptCompilation/CompilationPipeline.cs index c2d37818b2..413df46f19 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/CompilationPipeline.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/CompilationPipeline.cs @@ -10,6 +10,7 @@ using UnityEditor.Scripting.Compilers; using sc = UnityEditor.Scripting.ScriptCompilation; using UnityEditorInternal; +using UnityEngine; namespace UnityEditor.Compilation { @@ -37,7 +38,8 @@ public ScriptCompilerOptions() public enum AssembliesType { Editor = 0, - Player = 1 + Player = 1, + PlayerWithoutTestAssemblies = 2, } public enum AssemblyDefinitionReferenceType @@ -101,11 +103,18 @@ public class ResponseFileData { public string[] Defines; public string[] FullPathReferences; + public ResponseFileReference[] References; public string[] Errors; public string[] OtherArguments; public bool Unsafe; } + public struct ResponseFileReference + { + public string FullPathReference; + public string Alias; + } + public struct AssemblyDefinitionPlatform { public string Name { get; private set; } @@ -205,15 +214,22 @@ public static Assembly[] GetAssemblies() } public static Assembly[] GetAssemblies(AssembliesType assembliesType) + { + return GetAssemblies(EditorCompilationInterface.Instance, assembliesType); + } + + internal static Assembly[] GetAssemblies(EditorCompilation editorCompilation, AssembliesType assembliesType) { var options = EditorCompilationInterface.GetAdditionalEditorScriptCompilationOptions(); switch (assembliesType) { case AssembliesType.Editor: - return GetEditorAssemblies(EditorCompilationInterface.Instance, options, null); + return GetEditorAssemblies(editorCompilation, options | EditorScriptCompilationOptions.BuildingIncludingTestAssemblies, null); case AssembliesType.Player: - return GetPlayerAssemblies(EditorCompilationInterface.Instance, options, null); + return GetPlayerAssemblies(editorCompilation, options | EditorScriptCompilationOptions.BuildingIncludingTestAssemblies, null); + case AssembliesType.PlayerWithoutTestAssemblies: + return GetPlayerAssemblies(editorCompilation, options, null); default: throw new ArgumentOutOfRangeException("assembliesType"); } @@ -268,6 +284,17 @@ public static AssemblyDefinitionPlatform[] GetAssemblyDefinitionPlatforms() return assemblyDefinitionPlatforms; } + public static string[] GetDefinesFromAssemblyName(string assemblyName) + { + return GetDefinesFromAssemblyName(EditorCompilationInterface.Instance, assemblyName); + } + + internal static string[] GetDefinesFromAssemblyName(EditorCompilation editorCompilation, string assemblyName) + { + var assembly = GetAssemblies().FirstOrDefault(x => x.name == assemblyName); + return assembly?.defines; + } + public static string[] GetPrecompiledAssemblyNames() { return GetPrecompiledAssemblyNames(EditorCompilationInterface.Instance); @@ -282,6 +309,11 @@ internal static string[] GetPrecompiledAssemblyNames(EditorCompilation editorCom .ToArray(); } + public static bool IsDefineConstraintsCompatible(string[] defines, string[] defineConstraints) + { + return DefineConstraintsHelper.IsDefineConstraintsCompatible(defines, defineConstraints); + } + [Flags] public enum PrecompiledAssemblySources { @@ -342,16 +374,14 @@ internal static string GetPrecompiledAssemblyPathFromAssemblyName(string assembl return null; } - internal static Assembly[] GetEditorAssemblies(EditorCompilation editorCompilation, EditorScriptCompilationOptions additionalOptions, string[] defines) + private static Assembly[] GetEditorAssemblies(EditorCompilation editorCompilation, EditorScriptCompilationOptions additionalOptions, string[] defines) { - var scriptAssemblies = editorCompilation.GetAllEditorScriptAssemblies(additionalOptions, defines); + var scriptAssemblies = editorCompilation.GetAllScriptAssemblies(EditorScriptCompilationOptions.BuildingForEditor | additionalOptions, defines); return ToAssemblies(scriptAssemblies); } internal static Assembly[] GetPlayerAssemblies(EditorCompilation editorCompilation, EditorScriptCompilationOptions options, string[] defines) { - options |= EditorScriptCompilationOptions.BuildingIncludingTestAssemblies; - var group = EditorUserBuildSettings.activeBuildTargetGroup; var target = EditorUserBuildSettings.activeBuildTarget; diff --git a/Editor/Mono/Scripting/ScriptCompilation/CustomScriptAssembly.cs b/Editor/Mono/Scripting/ScriptCompilation/CustomScriptAssembly.cs index cfe95cdf29..b76c549a0e 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/CustomScriptAssembly.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/CustomScriptAssembly.cs @@ -62,6 +62,14 @@ class CustomScriptAssemblyData public string[] defineConstraints; public VersionDefine[] versionDefines; + static Dictionary renamedReferences = new Dictionary(StringComparer.Ordinal); + + static CustomScriptAssemblyData() + { + renamedReferences["Unity.RenderPipelines.Lightweight.Editor"] = "Unity.RenderPipelines.Universal.Editor"; + renamedReferences["Unity.RenderPipelines.Lightweight.Runtime"] = "Unity.RenderPipelines.Universal.Runtime"; + } + public static CustomScriptAssemblyData FromJson(string json) { var assemblyData = FromJsonNoFieldValidation(json); @@ -77,6 +85,7 @@ public static CustomScriptAssemblyData FromJsonNoFieldValidation(string json) assemblyData.autoReferenced = true; UnityEngine.JsonUtility.FromJsonOverwrite(json, assemblyData); + UpdateRenamedReferences(assemblyData); assemblyData.UpdateLegacyData(); if (assemblyData == null) @@ -93,6 +102,11 @@ public void ValidateFields() if ((excludePlatforms != null && excludePlatforms.Length > 0) && (includePlatforms != null && includePlatforms.Length > 0)) throw new System.Exception("Both 'excludePlatforms' and 'includePlatforms' are set."); + + if (autoReferenced && UnityCodeGenHelpers.IsCodeGen(name, includesExtension: false)) + { + throw new Exception($"Assembly '{name}' is a CodeGen assembly and cannot be Auto Referenced"); + } } public static string ToJson(CustomScriptAssemblyData data) @@ -100,6 +114,42 @@ public static string ToJson(CustomScriptAssemblyData data) return UnityEngine.JsonUtility.ToJson(data, true); } + static void UpdateRenamedReferences(CustomScriptAssemblyData data) + { + if (data.references == null || data.references.Length == 0) + return; + + HashSet additionalReferences = null; + + for (int i = 0; i < data.references.Length; ++i) + { + var reference = data.references[i]; + string newReference; + + if (!renamedReferences.TryGetValue(reference, out newReference)) + continue; + + if (additionalReferences == null) + additionalReferences = new HashSet(); + + additionalReferences.Add(newReference); + } + + if (additionalReferences != null && additionalReferences.Count() > 0) + { + for (int i = 0; i < data.references.Length; ++i) + { + var reference = data.references[i]; + + if (additionalReferences.Contains(reference)) + additionalReferences.Remove(reference); + } + + if (additionalReferences.Count() > 0) + data.references = data.references.Concat(additionalReferences).ToArray(); + } + } + [Serializable] private class CustomScriptAssemblyWithLegacyData : CustomScriptAssemblyData { diff --git a/Editor/Mono/Scripting/ScriptCompilation/DefineConstraintsHelper.cs b/Editor/Mono/Scripting/ScriptCompilation/DefineConstraintsHelper.cs index a4a2237580..5af84d5a28 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/DefineConstraintsHelper.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/DefineConstraintsHelper.cs @@ -3,6 +3,7 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; +using System.Collections.Generic; using System.Linq; using UnityEngine.Scripting; @@ -11,32 +12,66 @@ namespace UnityEditor.Scripting.ScriptCompilation internal static class DefineConstraintsHelper { public const string Not = "!"; + public const string Or = "||"; [RequiredByNativeCode] public static bool IsDefineConstraintsCompatible(string[] defines, string[] defineConstraints) { - var expectedDefines = defineConstraints?.Where(x => !x.StartsWith(Not)).ToList(); - if ((defines == null || !defines.Any()) && (expectedDefines == null || !expectedDefines.Any())) + if (defines == null && defineConstraints == null || defineConstraints == null) { return true; } - if (defineConstraints == null) + bool[] defineConstraintsValidity; + GetDefineConstraintsValidity(defines, defineConstraints, out defineConstraintsValidity); + + return defineConstraintsValidity.All(c => c); + } + + static void GetDefineConstraintsValidity(string[] defines, string[] defineConstraints, out bool[] defineConstraintsValidity) + { + defineConstraintsValidity = new bool[defineConstraints.Length]; + + for (int i = 0; i < defineConstraints.Length; ++i) { - return true; + defineConstraintsValidity[i] = IsDefineConstraintValid(defines, defineConstraints[i]); } + } + + internal static bool IsDefineConstraintValid(string[] defines, string defineConstraints) + { + var splitDefines = new HashSet(defineConstraints.Split(new[] { Or }, StringSplitOptions.RemoveEmptyEntries)); + + var notExpectedDefines = new HashSet(splitDefines.Where(x => x.StartsWith(Not)).Select(x => x.Substring(1))); + var expectedDefines = new HashSet(splitDefines.Where(x => !x.StartsWith(Not))); if (defines == null) { - return false; + if (expectedDefines.Count > 0) + { + return false; + } + return true; + } + + if (expectedDefines.Overlaps(notExpectedDefines)) + { + var complement = new HashSet(expectedDefines); + expectedDefines.ExceptWith(notExpectedDefines); + notExpectedDefines.ExceptWith(complement); } - var notExpectedDefines = defineConstraints.Where(x => x.StartsWith(Not)).Select(x => x.Substring(1)).ToList(); - if (!expectedDefines.All(defines.Contains) || notExpectedDefines.Any(defines.Contains)) + if (notExpectedDefines.Count > 0 && expectedDefines.Count == 0) { - return false; + return !notExpectedDefines.Any(defines.Contains); } - return true; + + if (expectedDefines.Count > 0 && notExpectedDefines.Count == 0) + { + return expectedDefines.Any(defines.Contains); + } + + return expectedDefines.Any(defines.Contains) || !notExpectedDefines.Any(defines.Contains); } } } diff --git a/Editor/Mono/Scripting/ScriptCompilation/EditorBuildRules.cs b/Editor/Mono/Scripting/ScriptCompilation/EditorBuildRules.cs index 0a5522d877..13b7f25bad 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/EditorBuildRules.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/EditorBuildRules.cs @@ -134,11 +134,6 @@ public override int GetHashCode() return hashCode; } } - - public List GetResponseFiles() - { - return Language?.CreateResponseFileProvider().Get(PathPrefix); - } } public class CompilationAssemblies @@ -376,10 +371,22 @@ public static ScriptAssembly[] GetAllScriptAssemblies(Dictionary assemblySourceFiles.Add(AssetPath.Combine(projectDirectory, scriptFile)); } - return ToScriptAssemblies(targetAssemblyFiles, settings, assemblies, runUpdaterAssemblies); + return ToScriptAssemblies(targetAssemblyFiles, settings, assemblies, runUpdaterAssemblies).ScriptAssemblies; + } + + public class ScriptAssembliesResult + { + public ScriptAssembliesResult(ScriptAssembly[] scriptAssemblies, bool pendingCodeGenAssembly) + { + ScriptAssemblies = scriptAssemblies; + PendingCodeGenAssembly = pendingCodeGenAssembly; + } + + public bool PendingCodeGenAssembly { get; private set; } + public ScriptAssembly[] ScriptAssemblies { get; private set; } } - public static ScriptAssembly[] GenerateChangedScriptAssemblies(GenerateChangedScriptAssembliesArgs args) + public static ScriptAssembliesResult GenerateChangedScriptAssemblies(GenerateChangedScriptAssembliesArgs args) { var dirtyTargetAssemblies = new Dictionary>(); @@ -495,7 +502,7 @@ public static ScriptAssembly[] GenerateChangedScriptAssemblies(GenerateChangedSc // Return empty array in case of no dirty target assemblies if (dirtyTargetAssemblies.Count == 0) - return new ScriptAssembly[0]; + return new ScriptAssembliesResult(new ScriptAssembly[0], false); // Collect any TargetAssemblies that reference the dirty TargetAssemblies, as they will also be dirty. int dirtyAssemblyCount; @@ -575,13 +582,12 @@ public static ScriptAssembly[] GenerateChangedScriptAssemblies(GenerateChangedSc foreach (var removeAssembly in args.NotCompiledTargetAssemblies) dirtyTargetAssemblies.Remove(removeAssembly); - // Convert TargetAssemblies to ScriptAssembiles var scriptAssemblies = ToScriptAssemblies(dirtyTargetAssemblies, args.Settings, args.Assemblies, args.RunUpdaterAssemblies); return scriptAssemblies; } - internal static ScriptAssembly[] ToScriptAssemblies(IDictionary> targetAssemblies, ScriptAssemblySettings settings, + internal static ScriptAssembliesResult ToScriptAssemblies(IDictionary> targetAssemblies, ScriptAssemblySettings settings, CompilationAssemblies assemblies, HashSet runUpdaterAssemblies) { var scriptAssemblies = new ScriptAssembly[targetAssemblies.Count]; @@ -633,15 +639,25 @@ internal static ScriptAssembly[] ToScriptAssemblies(IDictionary !UnityCodeGenHelpers.IsCodeGen(t.Filename)); // Setup ScriptAssembly references + bool hasCodeGenScriptAssembly = false; index = 0; foreach (var entry in targetAssemblies) - AddScriptAssemblyReferences(ref scriptAssemblies[index++], entry.Key, settings, + { + var scriptAssembly = scriptAssemblies[index++]; + AddScriptAssemblyReferences(ref scriptAssembly, entry.Key, settings, assemblies, targetToScriptAssembly); - return scriptAssemblies; + if (UnityCodeGenHelpers.IsCodeGen(entry.Key.Filename)) + { + hasCodeGenScriptAssembly = true; + UnityCodeGenHelpers.UpdateCodeGenScriptAssembly(ref scriptAssembly); + } + } + + return new ScriptAssembliesResult(scriptAssemblies, hasCodeGenScriptAssembly); } static bool IsPrecompiledAssemblyCompatibleWithScriptAssembly(PrecompiledAssembly compiledAssembly, ScriptAssembly scriptAssembly) diff --git a/Editor/Mono/Scripting/ScriptCompilation/EditorCompilation.cs b/Editor/Mono/Scripting/ScriptCompilation/EditorCompilation.cs index 13f40a29bf..985432b05a 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/EditorCompilation.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/EditorCompilation.cs @@ -8,10 +8,13 @@ using System.Linq; using System.Runtime.InteropServices; using System.Text.RegularExpressions; +using Unity.CompilationPipeline.Common.Diagnostics; +using Unity.CompilationPipeline.Common.ILPostProcessing; using UnityEditor.Compilation; using UnityEditor.Modules; using UnityEditor.Scripting.Compilers; using UnityEditorInternal; +using UnityEngine; using UnityEngine.Profiling; using CompilerMessage = UnityEditor.Scripting.Compilers.CompilerMessage; using CompilerMessageType = UnityEditor.Scripting.Compilers.CompilerMessageType; @@ -183,6 +186,8 @@ public override void PostprocessMessage(ref CompilerMessage message) public event Action assemblyCompilationStarted; public event Action assemblyCompilationFinished; + public bool IsCodeGenAssemblyChanged { get; set; } + static EditorCompilation() {} public void Initialize() @@ -217,8 +222,6 @@ internal void SetAssetPathsMetaData(AssetPathMetaData[] assetPathMetaDatas) .SelectMany(x => x.VersionMetaDatas ?? new AssetPathVersionMetaData[0]) .Distinct(assetPathVersionMetaDataComparer) .ToDictionary(x => x.Name, x => x.Version); - - SetAllTargetAssemblyVersionDefines(customTargetAssemblies, m_AllDistinctVersionMetaDatas); } internal AssetPathMetaData[] GetAssetPathsMetaData() @@ -274,6 +277,17 @@ public void DirtyAllScripts() areAllScriptsDirty = true; } + public void DirtyAllNonCodeGenAssemblies() + { + foreach (KeyValuePair customTargetAssembly in customTargetAssemblies) + { + if (!UnityCodeGenHelpers.IsCodeGen(customTargetAssembly.Key)) + { + dirtyTargetAssemblies.Add(customTargetAssembly.Value); + } + } + } + public void DirtyScript(string path, string assemblyFilename) { allScripts[path] = assemblyFilename; @@ -447,6 +461,27 @@ public void GetAssemblyDefinitionReferencesWithMissingAssemblies(out List predefinedAssemblyNames = null; // To check if a path prefix is already being used we use a Dictionary where the key is the prefix and the value is the file path. - var prefixToFilePathLookup = customScriptAssemblyReferences.ToDictionary(x => x.PathPrefix, x => new List() { x.FilePath }, StringComparer.OrdinalIgnoreCase); + var prefixToFilePathLookup = customScriptAssemblyReferences.ToDictionary(x => x.PathPrefix, x => new List(){ x.FilePath }, StringComparer.OrdinalIgnoreCase); ClearCompilationSetupErrorFlags(CompilationSetupErrorFlags.loadError); @@ -1005,7 +1040,6 @@ public Exception[] SetAllCustomScriptAssemblyJsonContents(string[] paths, string duplicateFilePaths = new List(); prefixToFilePathLookup[loadedCustomScriptAssembly.PathPrefix] = duplicateFilePaths; } - duplicateFilePaths.Add(loadedCustomScriptAssembly.FilePath); } } @@ -1074,7 +1108,7 @@ public Exception[] SetAllCustomScriptAssemblyJsonContents(string[] paths, string var updateCustomTargetAssembliesExceptions = UpdateCustomTargetAssemblies(); exceptions.AddRange(updateCustomTargetAssembliesExceptions); - SetAllTargetAssemblyVersionDefines(customTargetAssemblies, m_AllDistinctVersionMetaDatas); + return exceptions.ToArray(); } @@ -1100,7 +1134,7 @@ public void DeleteUnusedAssemblies(ScriptAssemblySettings settings) { // This is called in GetTargetAssembliesWithScripts and is required for compilation to // be set up correctly. Since we early out here, we need to call this here. - SetAllTargetAssemblyGlobalDefines(customTargetAssemblies, EditorBuildRules.GetPredefinedTargetAssemblies(), m_AllDistinctVersionMetaDatas, settings); + UpdateAllTargetAssemblyDefines(customTargetAssemblies, EditorBuildRules.GetPredefinedTargetAssemblies(), m_AllDistinctVersionMetaDatas, settings); return; } @@ -1352,7 +1386,8 @@ internal CompileStatus CompileScripts(ScriptAssemblySettings scriptAssemblySetti RunUpdaterAssemblies = runScriptUpdaterAssemblies }; - var scriptAssemblies = EditorBuildRules.GenerateChangedScriptAssemblies(args); + EditorBuildRules.ScriptAssembliesResult changedScriptAssemblies = EditorBuildRules.GenerateChangedScriptAssemblies(args); + ScriptAssembly[] scriptAssemblies = changedScriptAssemblies.ScriptAssemblies; foreach (var customTargetAssembly in args.NoScriptsCustomTargetAssemblies) { @@ -1389,7 +1424,7 @@ internal CompileStatus CompileScripts(ScriptAssemblySettings scriptAssemblySetti if (!scriptAssemblies.Any()) return CompileStatus.Idle; - bool compiling = CompileScriptAssemblies(scriptAssemblies, scriptAssemblySettings, tempBuildDirectory, options, CompilationTaskOptions.StopOnFirstError, CompileScriptAssembliesOptions.none); + bool compiling = CompileScriptAssemblies(scriptAssemblies, scriptAssemblySettings, tempBuildDirectory, options, CompilationTaskOptions.StopOnFirstError, CompileScriptAssembliesOptions.none, changedScriptAssemblies.PendingCodeGenAssembly); return compiling ? CompileStatus.CompilationStarted : CompileStatus.Idle; } @@ -1404,7 +1439,17 @@ internal bool CompileCustomScriptAssemblies(ScriptAssemblySettings scriptAssembl { DeleteUnusedAssemblies(); var scriptAssemblies = GetAllScriptAssembliesOfType(scriptAssemblySettings, EditorBuildRules.TargetAssemblyType.Custom); - return CompileScriptAssemblies(scriptAssemblies, scriptAssemblySettings, tempBuildDirectory, options, CompilationTaskOptions.None, CompileScriptAssembliesOptions.skipSetupChecks); + + bool hasPreprocessor = false; + foreach (var scriptAssembly in scriptAssemblies) + { + if (UnityCodeGenHelpers.IsCodeGen(scriptAssembly.Filename)) + { + hasPreprocessor = true; + } + } + + return CompileScriptAssemblies(scriptAssemblies, scriptAssemblySettings, tempBuildDirectory, options, CompilationTaskOptions.None, CompileScriptAssembliesOptions.skipSetupChecks, hasPreprocessor); } internal bool CompileScriptAssemblies(ScriptAssembly[] scriptAssemblies, @@ -1412,7 +1457,8 @@ internal bool CompileScriptAssemblies(ScriptAssembly[] scriptAssemblies, string tempBuildDirectory, EditorScriptCompilationOptions options, CompilationTaskOptions compilationTaskOptions, - CompileScriptAssembliesOptions compileScriptAssembliesOptions) + CompileScriptAssembliesOptions compileScriptAssembliesOptions, + bool pendingCodeGenAssembly = false) { StopAllCompilation(); @@ -1436,6 +1482,16 @@ internal bool CompileScriptAssemblies(ScriptAssembly[] scriptAssemblies, if (!Directory.Exists(tempBuildDirectory)) Directory.CreateDirectory(tempBuildDirectory); + var allTargetAssemblies = new Dictionary(customTargetAssemblies); + foreach (var predefinedTargetAssembly in EditorBuildRules.GetPredefinedTargetAssemblies()) + { + allTargetAssemblies.Add(predefinedTargetAssembly.Filename, predefinedTargetAssembly); + } + + var findReferences = new FindReferences(allTargetAssemblies, scriptAssemblySettings); + var fullPathToTempOutputFolder = Path.GetFullPath(tempBuildDirectory); + ILPostProcessor[] ilPostProcessors = null; + // Compile to tempBuildDirectory compilationTask = new CompilationTask(scriptAssemblies, tempBuildDirectory, "Editor Compilation", options, compilationTaskOptions, maxConcurrentCompilers); @@ -1446,6 +1502,10 @@ internal bool CompileScriptAssemblies(ScriptAssembly[] scriptAssemblies, compilationTask.OnCompilationTaskFinished += (context) => { + if (!compilationTask.CompileErrors) + { + IsCodeGenAssemblyChanged = pendingCodeGenAssembly; + } InvokeCompilationFinished(context); }; @@ -1466,14 +1526,54 @@ internal bool CompileScriptAssemblies(ScriptAssembly[] scriptAssemblies, assembly.GeneratedResponseFile = null; var assemblyOutputPath = AssetPath.Combine(scriptAssemblySettings.OutputDirectory, assembly.Filename); - Console.WriteLine("- Finished compile {0}", assemblyOutputPath); + var hasCompileError = messages.Any(m => m.type == CompilerMessageType.Error); + if (!pendingCodeGenAssembly && !hasCompileError) + { + if (ilPostProcessors == null) + { + ilPostProcessors = FindAllPostProcessors(); + } + + if (!UnityCodeGenHelpers.IsCodeGen(assembly.Filename)) + { + try + { + List diagnostics = RunILPostProcessors(ilPostProcessors, assembly, fullPathToTempOutputFolder, findReferences); + foreach (var message in diagnostics) + { + if (message.DiagnosticType == DiagnosticType.Error) + { + hasCompileError = true; + } + messages.Add(new CompilerMessage + { + assemblyName = message.File, + message = message.MessageData, + type = message.DiagnosticType == DiagnosticType.Error ? CompilerMessageType.Error : CompilerMessageType.Warning, + }); + } + } + catch (Exception exception) + { + messages.Add(new CompilerMessage + { + assemblyName = assembly.Filename, + message = $"Something went wrong while Post Processing the assembly ({assembly.Filename}) : {Environment.NewLine} {exception.Message} {Environment.NewLine}{exception.StackTrace}", + type = CompilerMessageType.Error, + }); + hasCompileError = true; + } + } + } + + Console.WriteLine("- Finished compile {0}", assemblyOutputPath); changedAssemblies.Add(assembly.Filename); if (runScriptUpdaterAssemblies.Contains(assembly.Filename)) runScriptUpdaterAssemblies.Remove(assembly.Filename); - if (messages.Any(m => m.type == CompilerMessageType.Error)) + if (hasCompileError) { AddUnitySpecificErrorMessages(assembly, messages); @@ -1497,6 +1597,69 @@ internal bool CompileScriptAssemblies(ScriptAssembly[] scriptAssemblies, return true; } + static ILPostProcessor[] FindAllPostProcessors() + { + TypeCache.TypeCollection typesDerivedFrom = TypeCache.GetTypesDerivedFrom(); + ILPostProcessor[] ilPostProcessors = new ILPostProcessor[typesDerivedFrom.Count]; + + for (int i = 0; i < typesDerivedFrom.Count; i++) + { + try + { + ilPostProcessors[i] = (ILPostProcessor)Activator.CreateInstance(typesDerivedFrom[i]); + } + catch (Exception exception) + { + Console.WriteLine($"Could not create ILPostProcessor ({typesDerivedFrom[i].FullName}):{Environment.NewLine}{exception.StackTrace}"); + } + } + + return ilPostProcessors; + } + + static List RunILPostProcessors(ILPostProcessor[] ilPostProcessors, ScriptAssembly assembly, string outputTempPath, FindReferences findReferences) + { + var assemblyPath = Path.Combine(outputTempPath, assembly.Filename); + + var resultMessages = new List(); + if (!File.Exists(assemblyPath)) + { + resultMessages.Add(new DiagnosticMessage + { + File = assemblyPath, + MessageData = $"Could not find {assemblyPath} for post processing", + DiagnosticType = DiagnosticType.Error, + }); + } + + bool isILProcessed = false; + var ilPostProcessCompiledAssembly = new ILPostProcessCompiledAssembly(assembly, outputTempPath, findReferences); + + InMemoryAssembly postProcessedInMemoryAssembly = null; + foreach (var ilPostProcessor in ilPostProcessors) + { + Console.WriteLine($"IL PostProcessor {ilPostProcessor.GetType().Name} processing: {assembly.Filename}"); + var ilPostProcessResult = ilPostProcessor.Process(ilPostProcessCompiledAssembly); + postProcessedInMemoryAssembly = ilPostProcessResult?.InMemoryAssembly; + if (ilPostProcessResult?.InMemoryAssembly != null) + { + isILProcessed = true; + ilPostProcessCompiledAssembly.InMemoryAssembly = postProcessedInMemoryAssembly; + } + + if (ilPostProcessResult?.Diagnostics != null) + { + resultMessages.AddRange(ilPostProcessResult.Diagnostics); + } + } + if (isILProcessed) + { + ilPostProcessCompiledAssembly.WriteAssembly(); + } + + return resultMessages; + } + static void RunScriptUpdater( ScriptAssembly assembly, string tempBuildDirectory, @@ -1791,7 +1954,7 @@ public TargetAssemblyInfo[] GetTargetAssembliesWithScripts(EditorScriptCompilati public TargetAssemblyInfo[] GetTargetAssembliesWithScripts(ScriptAssemblySettings settings) { - SetAllTargetAssemblyGlobalDefines(customTargetAssemblies, EditorBuildRules.GetPredefinedTargetAssemblies(), m_AllDistinctVersionMetaDatas, settings); + UpdateAllTargetAssemblyDefines(customTargetAssemblies, EditorBuildRules.GetPredefinedTargetAssemblies(), m_AllDistinctVersionMetaDatas, settings); var targetAssemblies = EditorBuildRules.GetTargetAssembliesWithScripts(allScripts, projectDirectory, customTargetAssemblies, settings); @@ -1887,7 +2050,7 @@ public ScriptAssembly[] GetAllScriptAssemblies(EditorScriptCompilationOptions op settings.ExtraGeneralDefines = defines; } - SetAllTargetAssemblyGlobalDefines(customTargetAssemblies, EditorBuildRules.GetPredefinedTargetAssemblies(), m_AllDistinctVersionMetaDatas, settings); + UpdateAllTargetAssemblyDefines(customTargetAssemblies, EditorBuildRules.GetPredefinedTargetAssemblies(), m_AllDistinctVersionMetaDatas, settings); var assemblies = new EditorBuildRules.CompilationAssemblies { @@ -1901,132 +2064,88 @@ public ScriptAssembly[] GetAllScriptAssemblies(EditorScriptCompilationOptions op return EditorBuildRules.GetAllScriptAssemblies(allScripts, projectDirectory, settings, assemblies, runScriptUpdaterAssemblies); } - private static void SetAllTargetAssemblyVersionDefines(IDictionary customScriptAssemblies, Dictionary assetPathVersionMetaDatas) + // TODO: Get rid of calls to this method and ensure that the defines are always setup correctly at all times. + private static void UpdateAllTargetAssemblyDefines(IDictionary customScriptAssemblies, EditorBuildRules.TargetAssembly[] predefinedTargetAssemblies, Dictionary assetPathVersionMetaDatas, ScriptAssemblySettings settings) { + var allTargetAssemblies = customScriptAssemblies.Values.ToArray() + .Concat(predefinedTargetAssemblies ?? new EditorBuildRules.TargetAssembly[0]); + var semVersionRangesFactory = new SemVersionRangesFactory(); - foreach (var targetAssembly in customScriptAssemblies.Values) - { - var defines = GetTargetAssemblyVersionDefines(assetPathVersionMetaDatas, targetAssembly.VersionDefines, semVersionRangesFactory); - targetAssembly.Defines = defines; - } - } + string[] editorOnlyCompatibleDefines = null; - public EditorBuildRules.TargetAssembly GetTargetAssemblyFromPath(string pathToScript) - { - string scriptAssemblyName; - if (allScripts.TryGetValue(pathToScript, out scriptAssemblyName)) + editorOnlyCompatibleDefines = InternalEditorUtility.GetCompilationDefines(settings.CompilationOptions, settings.BuildTargetGroup, settings.BuildTarget, ApiCompatibilityLevel.NET_4_6); + + var playerAssembliesDefines = InternalEditorUtility.GetCompilationDefines(settings.CompilationOptions, settings.BuildTargetGroup, settings.BuildTarget, settings.PredefinedAssembliesCompilerOptions.ApiCompatibilityLevel); + + foreach (var targetAssembly in allTargetAssemblies) { - EditorBuildRules.TargetAssembly targetAssembly; - if (customTargetAssemblies.TryGetValue(scriptAssemblyName, out targetAssembly)) - { - return targetAssembly; - } + SetTargetAssemblyDefines(targetAssembly, semVersionRangesFactory, assetPathVersionMetaDatas, editorOnlyCompatibleDefines, playerAssembliesDefines, settings); } - - return null; } - static string[] GetTargetAssemblyVersionDefines(Dictionary assetPathVersionMetaDatas, List versionDefines, - SemVersionRangesFactory semVersionRangesFactory) + private static void SetTargetAssemblyDefines(EditorBuildRules.TargetAssembly targetAssembly, SemVersionRangesFactory semVersionRangesFactory, Dictionary assetPathVersionMetaDatas, string[] editorOnlyCompatibleDefines, string[] playerAssembliesDefines, ScriptAssemblySettings settings) { - if (assetPathVersionMetaDatas == null || versionDefines == null) + string[] settingsExtraGeneralDefines = settings.ExtraGeneralDefines; + int populatedVersionDefinesCount = 0; + + string[] compilationDefines; + if ((targetAssembly.Flags & AssemblyFlags.EditorOnly) == AssemblyFlags.EditorOnly) { - return new string[0]; + compilationDefines = editorOnlyCompatibleDefines; } - - if (!assetPathVersionMetaDatas.Any()) + else { - return new string[0]; + compilationDefines = playerAssembliesDefines; } - int populatedVersionDefinesCount = 0; + string[] defines = new string[compilationDefines.Length + targetAssembly.VersionDefines.Count + settingsExtraGeneralDefines.Length]; - var defines = new string[versionDefines.Count]; - if (versionDefines.Count == 0) + Array.Copy(settingsExtraGeneralDefines, defines, settingsExtraGeneralDefines.Length); + populatedVersionDefinesCount += settingsExtraGeneralDefines.Length; + Array.Copy(compilationDefines, 0, defines, populatedVersionDefinesCount, compilationDefines.Length); + populatedVersionDefinesCount += compilationDefines.Length; + + if (assetPathVersionMetaDatas == null) { - return defines; + targetAssembly.Defines = defines; + return; } - var targetAssemblyVersionDefines = versionDefines; - foreach (var targetAssemblyVersionDefine in targetAssemblyVersionDefines) - { - if (!assetPathVersionMetaDatas.ContainsKey(targetAssemblyVersionDefine.name)) - { - continue; - } + var targetAssemblyVersionDefines = targetAssembly.VersionDefines; - if (string.IsNullOrEmpty(targetAssemblyVersionDefine.define)) + for (int i = 0; i < targetAssemblyVersionDefines.Count; i++) + { + if (!assetPathVersionMetaDatas.ContainsKey(targetAssemblyVersionDefines[i].name)) { continue; } - //If expression is empty, we add the dine regardless of the installed package version - if (string.IsNullOrEmpty(targetAssemblyVersionDefine.expression)) + if (string.IsNullOrEmpty(targetAssemblyVersionDefines[i].expression)) { - var define = targetAssemblyVersionDefine.define; - defines[populatedVersionDefinesCount] = define; - populatedVersionDefinesCount++; + var define = targetAssemblyVersionDefines[i].define; + if (!string.IsNullOrEmpty(define)) + { + defines[populatedVersionDefinesCount] = define; + populatedVersionDefinesCount++; + } continue; } - var versionDefineExpression = semVersionRangesFactory.GetExpression(targetAssemblyVersionDefine.expression); - var assetPathVersionMetaData = assetPathVersionMetaDatas[targetAssemblyVersionDefine.name]; + var versionDefineExpression = semVersionRangesFactory.GetExpression(targetAssemblyVersionDefines[i].expression); + var assetPathVersionMetaData = assetPathVersionMetaDatas[targetAssemblyVersionDefines[i].name]; var semVersion = SemVersionParser.Parse(assetPathVersionMetaData); if (versionDefineExpression.IsValid(semVersion)) { - defines[populatedVersionDefinesCount] = targetAssemblyVersionDefine.define; - populatedVersionDefinesCount++; - } - } - - Array.Resize(ref defines, populatedVersionDefinesCount); - return defines; - } - - // TODO: Get rid of calls to this method and ensure that the defines are always setup correctly at all times. - private static void SetAllTargetAssemblyGlobalDefines(IDictionary customScriptAssemblies, EditorBuildRules.TargetAssembly[] predefinedTargetAssemblies, Dictionary allDistinctVersionMetaDatas, ScriptAssemblySettings settings) - { - var allTargetAssemblies = customScriptAssemblies - .Values - .ToArray() - .Concat(predefinedTargetAssemblies ?? new EditorBuildRules.TargetAssembly[0]); - - ApiCompatibilityLevel apiCompatibilityLevel = ApiCompatibilityLevel.NET_4_6; - - string[] editorOnlyCompatibleDefines = InternalEditorUtility.GetCompilationDefines(settings.CompilationOptions, settings.BuildTargetGroup, settings.BuildTarget, apiCompatibilityLevel); - - var playerAssembliesDefines = InternalEditorUtility.GetCompilationDefines(settings.CompilationOptions, settings.BuildTargetGroup, settings.BuildTarget, settings.PredefinedAssembliesCompilerOptions.ApiCompatibilityLevel); - - var semVersionFactory = new SemVersionRangesFactory(); - - foreach (var targetAssembly in allTargetAssemblies) - { - if ((targetAssembly.Flags & AssemblyFlags.EditorOnly) == AssemblyFlags.EditorOnly) - { - SetTargetAssemblyDefines(targetAssembly, editorOnlyCompatibleDefines, allDistinctVersionMetaDatas, semVersionFactory, settings); - } - else - { - SetTargetAssemblyDefines(targetAssembly, playerAssembliesDefines, allDistinctVersionMetaDatas, semVersionFactory, settings); + var define = targetAssemblyVersionDefines[i].define; + if (!string.IsNullOrEmpty(define)) + { + defines[populatedVersionDefinesCount] = define; + populatedVersionDefinesCount++; + } } } - } - - private static void SetTargetAssemblyDefines(EditorBuildRules.TargetAssembly targetAssembly, string[] platformDefines, Dictionary allDistinctVersionMetaDatas, SemVersionRangesFactory semVersionFactory, ScriptAssemblySettings settings) - { - string[] settingsExtraGeneralDefines = settings.ExtraGeneralDefines; - var targetAssemblyVersionDefines = GetTargetAssemblyVersionDefines(allDistinctVersionMetaDatas, targetAssembly.VersionDefines, semVersionFactory); - int populatedVersionDefinesCount = targetAssemblyVersionDefines.Length; - - string[] defines = targetAssemblyVersionDefines; - Array.Resize(ref defines, defines.Length + settingsExtraGeneralDefines.Length + platformDefines.Length); - - Array.Copy(settingsExtraGeneralDefines, 0, defines, populatedVersionDefinesCount, settingsExtraGeneralDefines.Length); - populatedVersionDefinesCount += settingsExtraGeneralDefines.Length; - Array.Copy(platformDefines, 0, defines, populatedVersionDefinesCount, platformDefines.Length); - populatedVersionDefinesCount += platformDefines.Length; Array.Resize(ref defines, populatedVersionDefinesCount); targetAssembly.Defines = defines; @@ -2034,7 +2153,7 @@ private static void SetTargetAssemblyDefines(EditorBuildRules.TargetAssembly tar ScriptAssembly[] GetAllScriptAssembliesOfType(ScriptAssemblySettings settings, EditorBuildRules.TargetAssemblyType type) { - SetAllTargetAssemblyGlobalDefines(customTargetAssemblies, EditorBuildRules.GetPredefinedTargetAssemblies(), m_AllDistinctVersionMetaDatas, settings); + UpdateAllTargetAssemblyDefines(customTargetAssemblies, EditorBuildRules.GetPredefinedTargetAssemblies(), m_AllDistinctVersionMetaDatas, settings); var assemblies = new EditorBuildRules.CompilationAssemblies { @@ -2209,6 +2328,7 @@ public string[] GetAssemblyBuilderDefaultReferences(AssemblyBuilder assemblyBuil var options = ToEditorScriptCompilationOptions(assemblyBuilder.flags); var referencesOptions = ToUnityReferencesOptions(assemblyBuilder.referencesOptions); + var references = GetAssemblyBuilderDefaultReferences(scriptAssembly, options, referencesOptions); return references; diff --git a/Editor/Mono/Scripting/ScriptCompilation/EditorCompilationInterface.cs b/Editor/Mono/Scripting/ScriptCompilation/EditorCompilationInterface.cs index 6b9f41d8ed..e43b43e120 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/EditorCompilationInterface.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/EditorCompilationInterface.cs @@ -327,6 +327,18 @@ public static bool CompileCustomScriptAssemblies(EditorScriptCompilationOptions return EmitExceptionAsError(() => Instance.CompileCustomScriptAssemblies(definesOptions, platformGroup, platform), false); } + [RequiredByNativeCode] + public static bool ShouldRecompileNonCodeGenAssembliesAfterReload() + { + return EmitExceptionAsError(() => Instance.IsCodeGenAssemblyChanged, false); + } + + [RequiredByNativeCode] + public static void DirtyAllNonCodeGenAssemblies() + { + EmitExceptionAsError(() => Instance.DirtyAllNonCodeGenAssemblies()); + } + [RequiredByNativeCode] public static bool DoesProjectFolderHaveAnyDirtyScripts() { diff --git a/Editor/Mono/Scripting/ScriptCompilation/ExpressionTypeFactory.cs b/Editor/Mono/Scripting/ScriptCompilation/ExpressionTypeFactory.cs index da90bce30b..80a00d066c 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/ExpressionTypeFactory.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/ExpressionTypeFactory.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Linq; -using UnityEditor.Experimental.VFX; namespace UnityEditor.Scripting.ScriptCompilation { diff --git a/Editor/Mono/Scripting/ScriptCompilation/FindReferences.cs b/Editor/Mono/Scripting/ScriptCompilation/FindReferences.cs new file mode 100644 index 0000000000..8e35ea3f5c --- /dev/null +++ b/Editor/Mono/Scripting/ScriptCompilation/FindReferences.cs @@ -0,0 +1,137 @@ +// 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 Unity.CompilationPipeline.Common.ILPostProcessing; + +namespace UnityEditor.Scripting.ScriptCompilation +{ + [Flags] + internal enum FindReferencesQueryOptions + { + Direct = 1, + Indirect = 2, + Transitive = Indirect | Direct, + } + + internal class FindReferences + { + readonly Dictionary m_AllTargetAssemblies; + readonly Dictionary m_CompatibleTargetAssemblies = new Dictionary(); + readonly ScriptAssemblySettings m_AssemblySettings; + + readonly Dictionary> m_AssemblyNameReferences = + new Dictionary>(); + + public FindReferences(Dictionary targetAssemblies, + ScriptAssemblySettings assemblySettings) + { + m_AllTargetAssemblies = targetAssemblies; + m_AssemblySettings = assemblySettings; + } + + public HashSet Execute(string assembly, string[] searchReferences, + FindReferencesQueryOptions referencesOptions) + { + if (searchReferences.Length <= 0) + { + return new HashSet(); + } + + var searchQuery = new HashSet(searchReferences); + HashSet result = new HashSet(); + if ((referencesOptions & FindReferencesQueryOptions.Direct) == FindReferencesQueryOptions.Direct) + { + HashSet directResult = AllDirectReferences(m_AllTargetAssemblies[assembly]); + result.UnionWith(directResult); + result.IntersectWith(searchReferences); + } + + if ((referencesOptions & FindReferencesQueryOptions.Indirect) == FindReferencesQueryOptions.Indirect) + { + foreach (var reference in m_AllTargetAssemblies[assembly].References) + { + if (searchQuery.Count <= 0) + { + break; + } + result.UnionWith(FindReferencesRecursive(reference, searchQuery)); + } + } + + return result; + } + + private bool IsCompatibleCached(EditorBuildRules.TargetAssembly targetAssembly) + { + bool isCompatible; + if (m_CompatibleTargetAssemblies.TryGetValue(targetAssembly.Filename, out isCompatible)) + { + return isCompatible; + } + + isCompatible = targetAssembly.IsCompatibleFunc(m_AssemblySettings, targetAssembly.Defines ?? new string[0]); + m_CompatibleTargetAssemblies.Add(targetAssembly.Filename, isCompatible); + return isCompatible; + } + + private HashSet AllDirectReferences(EditorBuildRules.TargetAssembly targetAssembly) + { + HashSet references; + if (m_AssemblyNameReferences.TryGetValue(targetAssembly.Filename, out references)) + { + return references; + } + + references = new HashSet(); + foreach (var targetAssemblyReference in targetAssembly.References) + { + if (IsCompatibleCached(targetAssemblyReference)) + { + references.Add(targetAssemblyReference.Filename); + } + } + + foreach (var assemblyPrecompiledReference in targetAssembly.PrecompiledReferences) + { + var fileName = Path.GetFileName(assemblyPrecompiledReference.Path); + references.Add(fileName); + } + + m_AssemblyNameReferences.Add(targetAssembly.Filename, references); + return references; + } + + private List FindReferencesRecursive(EditorBuildRules.TargetAssembly targetAssembly, + HashSet searchFor) + { + var result = new List(searchFor.Count); + var allDirectReferences = AllDirectReferences(targetAssembly); + allDirectReferences.IntersectWith(searchFor); + result.AddRange(allDirectReferences); + + searchFor.ExceptWith(result); + if (!searchFor.Any()) + { + return result; + } + + foreach (var assemblyReference in targetAssembly.References) + { + if (!searchFor.Any()) + { + continue; + } + + var referenceResult = FindReferencesRecursive(assemblyReference, searchFor); + result.AddRange(referenceResult); + } + + return result; + } + } +} diff --git a/Editor/Mono/Scripting/ScriptCompilation/ILPostProcessCompiledAssembly.cs b/Editor/Mono/Scripting/ScriptCompilation/ILPostProcessCompiledAssembly.cs new file mode 100644 index 0000000000..42370bb97c --- /dev/null +++ b/Editor/Mono/Scripting/ScriptCompilation/ILPostProcessCompiledAssembly.cs @@ -0,0 +1,102 @@ +// 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 Unity.CompilationPipeline.Common.ILPostProcessing; +using UnityEditor.Scripting.ScriptCompilation; + +internal class ILPostProcessCompiledAssembly : ICompiledAssembly +{ + readonly ScriptAssembly m_ScriptAssembly; + readonly string m_OutputPath; + readonly FindReferences m_FindReferences; + InMemoryAssembly m_InMemoryAssembly; + + public ILPostProcessCompiledAssembly(ScriptAssembly scriptAssembly, string outputPath, FindReferences findReferences) + { + m_ScriptAssembly = scriptAssembly; + Name = Path.GetFileNameWithoutExtension(scriptAssembly.Filename); + References = scriptAssembly.GetAllReferences().Select(Path.GetFileName).ToArray(); + + m_OutputPath = outputPath; + m_FindReferences = findReferences; + } + + private InMemoryAssembly CreateOrGetInMemoryAssembly() + { + if (m_InMemoryAssembly != null) + { + return m_InMemoryAssembly; + } + + byte[] peData = File.ReadAllBytes(Path.Combine(m_OutputPath, m_ScriptAssembly.Filename)); + + var pdbFileName = Path.GetFileNameWithoutExtension(m_ScriptAssembly.Filename) + ".pdb"; + byte[] pdbData = File.ReadAllBytes(Path.Combine(m_OutputPath, pdbFileName)); + + m_InMemoryAssembly = new InMemoryAssembly(peData, pdbData); + return m_InMemoryAssembly; + } + + public InMemoryAssembly InMemoryAssembly + { + get { return CreateOrGetInMemoryAssembly(); } + set { m_InMemoryAssembly = value; } + } + + public string Name { get; set; } + public string[] References { get; set; } + + public ReferenceQueryResult HasReferences(ReferenceQueryInput input) + { + if (input.References == null) + { + throw new ArgumentNullException(nameof(input.References)); + } + + HashSet result = m_FindReferences.Execute(m_ScriptAssembly.Filename, input.References, (FindReferencesQueryOptions)input.Options); + var found = new bool[input.References.Length]; + var isAllReferencesFound = result.Any(); + for (int i = 0; i < input.References.Length; i++) + { + found[i] = result.Contains(input.References[i]); + isAllReferencesFound &= found[i]; + } + + return new ReferenceQueryResult(found, isAllReferencesFound); + } + + public bool HasReference(string reference, ReferencesQueryOptions options = ReferencesQueryOptions.Direct) + { + if (string.IsNullOrEmpty(reference)) + { + throw new ArgumentException(nameof(reference)); + } + + var hasReferencesResult = HasReferences(new ReferenceQueryInput() + { + References = new string[] { reference }, + Options = options + }); + return hasReferencesResult.HasAllReferences && hasReferencesResult.HasReference.All(x => x); + } + + public void WriteAssembly() + { + if (m_InMemoryAssembly == null) + { + throw new ArgumentException("InMemoryAssembly has never been accessed or modified"); + } + + var assemblyPath = Path.Combine(m_OutputPath, m_ScriptAssembly.Filename); + var pdbFileName = Path.GetFileNameWithoutExtension(m_ScriptAssembly.Filename) + ".pdb"; + var pdbPath = Path.Combine(m_OutputPath, pdbFileName); + + File.WriteAllBytes(assemblyPath, InMemoryAssembly.PeData); + File.WriteAllBytes(pdbPath, InMemoryAssembly.PdbData); + } +} diff --git a/Editor/Mono/Scripting/ScriptCompilation/ScriptAssembly.cs b/Editor/Mono/Scripting/ScriptCompilation/ScriptAssembly.cs index 6d9c1e6ef9..d660bac2c6 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/ScriptAssembly.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/ScriptAssembly.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using UnityEditor.Scripting.Compilers; using UnityEditor.Compilation; @@ -41,6 +42,7 @@ public bool BuildingDevelopmentBuild } } + [DebuggerDisplay("{Filename}")] class ScriptAssembly { public string OriginPath { get; set; } diff --git a/Editor/Mono/Scripting/ScriptCompilation/TestRunnerHelpers.cs b/Editor/Mono/Scripting/ScriptCompilation/TestRunnerHelpers.cs index bed0ce734e..54574816a3 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/TestRunnerHelpers.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/TestRunnerHelpers.cs @@ -17,6 +17,11 @@ static class TestRunnerHelpers public static bool ShouldAddTestRunnerReferences(EditorBuildRules.TargetAssembly targetAssembly) { + if (UnityCodeGenHelpers.IsCodeGen(targetAssembly.Filename)) + { + return false; + } + return !targetAssembly.References.Any(x => x.Filename.Contains(k_EngineTestRunnerAssemblyName) || x.Filename.Contains(k_EditorTestRunnerAssemblyName)) && !targetAssembly.Filename.Contains(k_EngineTestRunnerAssemblyName) && !targetAssembly.Filename.Contains(k_EditorTestRunnerAssemblyName) diff --git a/Editor/Mono/Scripting/ScriptCompilation/UnityCodeGenHelpers.cs b/Editor/Mono/Scripting/ScriptCompilation/UnityCodeGenHelpers.cs new file mode 100644 index 0000000000..14033e5ba0 --- /dev/null +++ b/Editor/Mono/Scripting/ScriptCompilation/UnityCodeGenHelpers.cs @@ -0,0 +1,56 @@ +// 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.IO; +using System.Linq; +using UnityEditor.Scripting.ScriptCompilation; +using UnityEditorInternal; +using UnityEngine; +using UnityEngine.Scripting; + +namespace UnityEditor.Scripting.ScriptCompilation +{ + internal static class UnityCodeGenHelpers + { + const string k_CodeGenSuffix = ".CodeGen"; + const string k_CodeGenPrefix = "Unity."; + + const string k_UnityEngineModules = "UnityEngine"; + const string k_UnityEngineModulesLower = "unityengine"; + + const string k_UnityEditorModules = "UnityEditor"; + const string k_UnityEditorModulesLower = "unityeditor"; + + public static bool IsCodeGen(string assemblyName, bool includesExtension = true) + { + var name = (includesExtension ? Path.GetFileNameWithoutExtension(assemblyName) : assemblyName); + var isCodeGen = name.StartsWith(k_CodeGenPrefix) && name.EndsWith(k_CodeGenSuffix, StringComparison.OrdinalIgnoreCase); + return isCodeGen; + } + + public static void UpdateCodeGenScriptAssembly(ref ScriptAssembly scriptAssembly) + { + scriptAssembly.ScriptAssemblyReferences = new ScriptAssembly[0]; + + int newReferenceCount = 0; + var references = new string[scriptAssembly.References.Length]; + + foreach (var reference in scriptAssembly.References) + { + var name = AssetPath.GetFileName(reference); + if (!Utility.FastStartsWith(name, k_UnityEngineModules, k_UnityEngineModulesLower) + && !Utility.FastStartsWith(name, k_UnityEditorModules, k_UnityEditorModulesLower)) + { + references[newReferenceCount] = reference; + newReferenceCount++; + } + } + var result = new string[newReferenceCount + 1]; + Array.Copy(references, result, newReferenceCount); + result[newReferenceCount] = AssetPath.Combine(EditorApplication.applicationContentsPath, "Managed", "Unity.CompilationPipeline.Common.dll"); + scriptAssembly.References = result; + } + } +} diff --git a/Editor/Mono/Scripting/ScriptCompilers.cs b/Editor/Mono/Scripting/ScriptCompilers.cs index a9a6dc4ab5..49bda722bb 100644 --- a/Editor/Mono/Scripting/ScriptCompilers.cs +++ b/Editor/Mono/Scripting/ScriptCompilers.cs @@ -9,7 +9,6 @@ using System.Runtime.InteropServices; using UnityEditor.Scripting.Compilers; using UnityEditor.Scripting.ScriptCompilation; -using UnityEngine.Scripting; namespace UnityEditor.Scripting { @@ -103,7 +102,24 @@ internal static SupportedLanguageStruct[] GetSupportedLanguageStructs() }).ToArray(); } - [RequiredByNativeCode] + internal static void GetClassAndNamespace(string file, string definedSymbols, out string outClassName, + out string outNamespace) + { + if (string.IsNullOrEmpty(file)) throw new ArgumentException("Invalid file"); + + string extension = GetExtensionOfSourceFile(file); + foreach (var lang in SupportedLanguages) + { + if (lang.GetExtensionICanCompile() == extension) + { + lang.GetClassAndNamespace(file, definedSymbols, out outClassName, out outNamespace); + return; + } + } + + throw new ApplicationException("Unable to find a suitable compiler"); + } + internal static string GetNamespace(string file, string definedSymbols) { if (string.IsNullOrEmpty(file)) throw new ArgumentException("Invalid file"); diff --git a/Editor/Mono/Settings/SettingsTreeView.cs b/Editor/Mono/Settings/SettingsTreeView.cs index a8fe73d809..a49561f5bc 100644 --- a/Editor/Mono/Settings/SettingsTreeView.cs +++ b/Editor/Mono/Settings/SettingsTreeView.cs @@ -159,10 +159,9 @@ private void BuildSettingsNodeTree(SettingsNode rootNode) foreach (var provider in providers) { if (rootName == null) - { rootName = provider.pathTokens[0]; - } - else if (rootName != provider.pathTokens[0]) + + if (rootName != provider.pathTokens[0]) { allChildrenUnderSameRoot = false; m_ListViewMode = false; diff --git a/Editor/Mono/Settings/SettingsWindow.cs b/Editor/Mono/Settings/SettingsWindow.cs index d6e610bda3..cc9cc80b24 100644 --- a/Editor/Mono/Settings/SettingsWindow.cs +++ b/Editor/Mono/Settings/SettingsWindow.cs @@ -26,8 +26,10 @@ internal class SettingsWindow : EditorWindow, IHasCustomMenu private SettingsTreeView m_TreeView; private VisualSplitter m_Splitter; private VisualElement m_SettingsPanel; + private VisualElement m_TreeViewContainer; private string m_SearchText; private bool m_SearchFieldGiveFocus; + const string k_SearchField = "SearchField"; private static class ImguiStyles { @@ -250,9 +252,34 @@ private void ProviderChanged(SettingsProvider lastSelectedProvider, SettingsProv } } + private void SetupWindowPosition() + { + var minWidth = Styles.window.GetFloat("min-width"); + var minHeight = Styles.window.GetFloat("min-height"); + minSize = new Vector2(minWidth, minHeight); + + // Center the window if it has never been opened by the user. + if (EditorPrefs.HasKey($"{this.GetType().FullName}h")) + return; // Do nothing if the window was opened previously. + + var initialWidth = Styles.window.GetFloat("-unity-initial-width"); + var initialHeight = Styles.window.GetFloat("-unity-initial-height"); + var containers = Resources.FindObjectsOfTypeAll(typeof(ContainerWindow)); + + Vector2 initialSize = new Vector2(Mathf.Min(initialWidth, Screen.width), Mathf.Min(initialHeight, Screen.height)); + foreach (ContainerWindow window in containers) + { + if (window.showMode == ShowMode.MainWindow) + { + position = new Rect(window.position.center - (initialSize / 2), initialSize); + break; + } + } + } + private void SetupUI() { - minSize = new Vector2(Styles.window.GetFloat("min-width"), Styles.window.GetFloat("min-height")); + SetupWindowPosition(); var root = rootVisualElement; root.AddStyleSheetPath("StyleSheets/SettingsWindowCommon.uss"); @@ -266,7 +293,7 @@ private void SetupUI() m_Splitter = new VisualSplitter { splitSize = Styles.window.GetInt("-unity-splitter-size") }; m_Splitter.AddToClassList("settings-splitter"); root.Add(m_Splitter); - var settingsTree = new IMGUIContainer(DrawTreeView) + m_TreeViewContainer = new IMGUIContainer(DrawTreeView) { style = { @@ -275,8 +302,8 @@ private void SetupUI() }, focusOnlyIfHasFocusableControls = false, }; - settingsTree.AddToClassList("settings-tree-imgui-container"); - m_Splitter.Add(settingsTree); + m_TreeViewContainer.AddToClassList("settings-tree-imgui-container"); + m_Splitter.Add(m_TreeViewContainer); m_SettingsPanel = new VisualElement() { @@ -294,6 +321,33 @@ private void DrawToolbar() { GUILayout.BeginHorizontal(EditorStyles.toolbar); GUILayout.FlexibleSpace(); + + var e = Event.current; + if (e.commandName == EventCommandNames.Find) + { + if (e.type == EventType.ExecuteCommand) + { + EditorGUI.FocusTextInControl(k_SearchField); + } + + if (e.type != EventType.Layout) + e.Use(); + } + + if (e.type == EventType.KeyDown) + { + if (e.keyCode == KeyCode.Escape || ((e.keyCode == KeyCode.UpArrow || e.keyCode == KeyCode.DownArrow) && + GUI.GetNameOfFocusedControl() == k_SearchField)) + { + m_SearchText = string.Empty; + HandleSearchFiltering(); + m_TreeViewContainer.Focus(); + GUIUtility.keyboardControl = m_TreeView.treeViewControlID; + Repaint(); + } + } + + GUI.SetNextControlName(k_SearchField); var searchText = EditorGUILayout.ToolbarSearchField(m_SearchText); if (searchText != m_SearchText) { @@ -370,7 +424,7 @@ private void DrawTreeView() if (m_SearchFieldGiveFocus) { m_SearchFieldGiveFocus = false; - GUI.FocusControl("SettingsSearchField"); + GUI.FocusControl(k_SearchField); } } diff --git a/Editor/Mono/ShaderUtil.bindings.cs b/Editor/Mono/ShaderUtil.bindings.cs index 670572ff23..7537b92404 100644 --- a/Editor/Mono/ShaderUtil.bindings.cs +++ b/Editor/Mono/ShaderUtil.bindings.cs @@ -11,7 +11,7 @@ using UnityEngine.Scripting; using ShaderPlatform = UnityEngine.Rendering.GraphicsDeviceType; using TextureDimension = UnityEngine.Rendering.TextureDimension; - +using UnityEngine.Experimental.Rendering; namespace UnityEditor { @@ -133,6 +133,17 @@ public enum ShaderPropertyType extern public static int GetComputeShaderMessageCount([NotNull] ComputeShader s); extern public static ShaderMessage[] GetComputeShaderMessages([NotNull] ComputeShader s); + extern public static int GetRayTracingShaderMessageCount([NotNull] RayTracingShader s); + extern public static ShaderMessage[] GetRayTracingShaderMessages([NotNull] RayTracingShader s); + extern public static int GetRayGenerationShaderCount([NotNull] RayTracingShader s); + extern public static string GetRayGenerationShaderName([NotNull] RayTracingShader s, int shaderIndex); + extern public static int GetMissShaderCount([NotNull] RayTracingShader s); + extern public static string GetMissShaderName([NotNull] RayTracingShader s, int shaderIndex); + extern public static int GetMissShaderRayPayloadSize([NotNull] RayTracingShader s, int shaderIndex); + extern public static int GetCallableShaderCount([NotNull] RayTracingShader s); + extern public static string GetCallableShaderName([NotNull] RayTracingShader s, int shaderIndex); + extern public static int GetCallableShaderParamSize([NotNull] RayTracingShader s, int shaderIndex); + private static void CheckPropertyIndex(Shader s, int idx) { if (idx < 0 || idx >= GetPropertyCount(s)) @@ -217,6 +228,9 @@ public static bool IsShaderPropertyNonModifiableTexureProperty(Shader s, int pro extern internal static int GetComputeShaderPlatformKernelCount(ComputeShader s, int platformIndex); extern internal static string GetComputeShaderPlatformKernelName(ComputeShader s, int platformIndex, int kernelIndex); + extern internal static int GetRayTracingShaderPlatformCount(RayTracingShader s); + extern internal static ShaderPlatform GetRayTracingShaderPlatformType(RayTracingShader s, int platformIndex); + extern internal static bool IsRayTracingShaderValidForPlatform(RayTracingShader s, ShaderPlatform renderer); extern internal static void CalculateLightmapStrippingFromCurrentScene(); extern internal static void CalculateFogStrippingFromCurrentScene(); diff --git a/Editor/Mono/Sprites/SpritePacker.cs b/Editor/Mono/Sprites/SpritePacker.cs index c80ffa830f..05aafa45dc 100644 --- a/Editor/Mono/Sprites/SpritePacker.cs +++ b/Editor/Mono/Sprites/SpritePacker.cs @@ -84,6 +84,7 @@ private static void RegenerateList() SetSelectedPolicy(kDefaultPolicy); } + // Called from SpritePacker::GetSelectedPolicyId() internal static string GetSelectedPolicyId() { RegenerateList(); diff --git a/Editor/Mono/Sprites/SpriteUtility.cs b/Editor/Mono/Sprites/SpriteUtility.cs index 8f877f3e4c..118f790e34 100644 --- a/Editor/Mono/Sprites/SpriteUtility.cs +++ b/Editor/Mono/Sprites/SpriteUtility.cs @@ -8,8 +8,6 @@ using UnityEngine; using UnityEngine.Experimental.Rendering; using System.Collections.Generic; -using UnityEditor.Experimental.U2D; -using UnityEditor.U2D.Interface; using UnityEngine.SceneManagement; using UnityEngine.U2D.Interface; using Object = UnityEngine.Object; diff --git a/Editor/Mono/Sprites/SpriteUtilityWindow.cs b/Editor/Mono/Sprites/SpriteUtilityWindow.cs index 0a97a909ba..791e8d6412 100644 --- a/Editor/Mono/Sprites/SpriteUtilityWindow.cs +++ b/Editor/Mono/Sprites/SpriteUtilityWindow.cs @@ -211,11 +211,6 @@ protected void DrawTexturespaceBackground() SpriteEditorUtility.EndLines(); } - private float Log2(float x) - { - return (float)(System.Math.Log(x) / System.Math.Log(2)); - } - protected void DrawTexture() { float mipLevel = Mathf.Min(m_MipLevel, TextureUtil.GetMipmapCount(m_Texture) - 1); diff --git a/Editor/Mono/SyncProject.cs b/Editor/Mono/SyncProject.cs new file mode 100644 index 0000000000..7a7a2438e6 --- /dev/null +++ b/Editor/Mono/SyncProject.cs @@ -0,0 +1,431 @@ +// 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.IO; +using System.Linq; +using System.Collections.Generic; +using Microsoft.Win32; +using UnityEditor.Callbacks; +using UnityEditor.VisualStudioIntegration; +using UnityEngine; +using UnityEngine.Scripting; +using UnityEditorInternal; + +namespace UnityEditor +{ + internal enum VisualStudioVersion + { + Invalid = 0, + VisualStudio2008 = 9, + VisualStudio2010 = 10, + VisualStudio2012 = 11, + VisualStudio2013 = 12, + VisualStudio2015 = 14, + VisualStudio2017 = 15, + VisualStudio2019 = 16, + } + + internal class VisualStudioPath + { + public string Path { get; set; } + public string Edition { get; set; } + + public VisualStudioPath(string path, string edition = "") + { + Path = path; + Edition = edition; + } + } + + [InitializeOnLoad] + internal partial class SyncVS : AssetPostprocessor + { + static bool s_AlreadySyncedThisDomainReload; + + static SyncVS() + { + Synchronizer = new SolutionSynchronizer(Directory.GetParent(Application.dataPath).FullName, new SolutionSynchronizationSettings()); + try + { + InstalledVisualStudios = GetInstalledVisualStudios() as Dictionary; + } + catch (Exception ex) + { + 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() + { + var vs = InstalledVisualStudios.OrderByDescending(kvp => kvp.Key).Select(kvp2 => kvp2.Value).FirstOrDefault(); + return vs == null ? null : vs.Last().Path; + } + + internal static readonly SolutionSynchronizer Synchronizer; + internal static Dictionary InstalledVisualStudios { get; private set; } + + internal class SolutionSynchronizationSettings : DefaultSolutionSynchronizationSettings + { + public override int VisualStudioVersion + { + get + { + var vs = ScriptEditorUtility.GetExternalScriptEditor(); + if (InstalledVisualStudios.ContainsKey(UnityEditor.VisualStudioVersion.VisualStudio2008) && + (vs != String.Empty) && + PathsAreEquivalent(InstalledVisualStudios[UnityEditor.VisualStudioVersion.VisualStudio2008].Last().Path, vs)) + return 9; + + return 10; + } + } + + public override string SolutionTemplate + { + get { return EditorPrefs.GetString("VSSolutionText", base.SolutionTemplate); } + } + + public override string GetProjectHeaderTemplate(ScriptingLanguage language) + { + return EditorPrefs.GetString("VSProjectHeader", base.GetProjectHeaderTemplate(language)); + } + + public override string GetProjectFooterTemplate(ScriptingLanguage language) + { + return EditorPrefs.GetString("VSProjectFooter", base.GetProjectFooterTemplate(language)); + } + + public override string EditorAssemblyPath + { + get { return UnityEditorInternal.InternalEditorUtility.GetEditorAssemblyPath(); } + } + + public override string EngineAssemblyPath + { + get { return UnityEditorInternal.InternalEditorUtility.GetEngineAssemblyPath(); } + } + + protected override string FrameworksPath() + { + return EditorApplication.applicationContentsPath; + } + + internal static bool IsOSX + { + get { return System.Environment.OSVersion.Platform == System.PlatformID.Unix; } + } + + internal static bool IsWindows + { + get { return !IsOSX && System.IO.Path.DirectorySeparatorChar == '\\' && System.Environment.NewLine == "\r\n"; } + } + } + + public static bool ProjectExists() + { + return Synchronizer.SolutionExists(); + } + + public static void CreateIfDoesntExist() + { + if (!Synchronizer.SolutionExists()) + { + Synchronizer.Sync(); + } + } + + class BuildTargetChangedHandler : Build.IActiveBuildTargetChanged + { + public int callbackOrder { get { return 0; } } + + public void OnActiveBuildTargetChanged(BuildTarget oldTarget, BuildTarget newTarget) + { + SyncVisualStudioProjectIfItAlreadyExists(); + } + } + + [RequiredByNativeCode] + public static void SyncVisualStudioProjectIfItAlreadyExists() + { + if (Synchronizer.SolutionExists()) + { + Synchronizer.Sync(); + } + } + + // For the time being this doesn't use the callback + public static void PostprocessSyncProject( + string[] importedAssets, + string[] addedAssets, + string[] deletedAssets, + string[] movedAssets, + string[] movedFromAssetPaths) + { + Synchronizer.SyncIfNeeded(addedAssets.Union(deletedAssets.Union(movedAssets.Union(movedFromAssetPaths))), importedAssets); + } + + public static void SyncIfFirstFileOpenSinceDomainLoad() + { + if (s_AlreadySyncedThisDomainReload) + return; + + s_AlreadySyncedThisDomainReload = true; + Synchronizer.Sync(); + } + + /// + /// Detects Visual Studio installations using the Windows registry + /// + /// + /// The detected Visual Studio installations + /// + private static IDictionary GetInstalledVisualStudios() + { + var versions = new Dictionary(); + + if (SolutionSynchronizationSettings.IsWindows) + { + foreach (VisualStudioVersion version in Enum.GetValues(typeof(VisualStudioVersion))) + { + if (version > VisualStudioVersion.VisualStudio2015) + continue; + + try + { + // Try COMNTOOLS environment variable first + string key = Environment.GetEnvironmentVariable(string.Format("VS{0}0COMNTOOLS", (int)version)); + if (!string.IsNullOrEmpty(key)) + { + string path = UnityEditor.Utils.Paths.Combine(key, "..", "IDE", "devenv.exe"); + if (File.Exists(path)) + { + versions[version] = new[] { new VisualStudioPath(path) }; + continue; + } + } + + // Try the proper registry key + key = GetRegistryValue( + string.Format(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\{0}.0", (int)version), "InstallDir"); + + // Try to fallback to the 32bits hive + if (string.IsNullOrEmpty(key)) + key = GetRegistryValue( + string.Format(@"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\{0}.0", (int)version), "InstallDir"); + + if (!string.IsNullOrEmpty(key)) + { + string path = UnityEditor.Utils.Paths.Combine(key, "devenv.exe"); + if (File.Exists(path)) + { + versions[version] = new[] { new VisualStudioPath(path) }; + continue; + } + } + + // Fallback to debugger key + key = GetRegistryValue( + // VS uses this key for the local debugger path + string.Format(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\{0}.0\Debugger", (int)version), "FEQARuntimeImplDll"); + if (!string.IsNullOrEmpty(key)) + { + string path = DeriveVisualStudioPath(key); + if (!string.IsNullOrEmpty(path) && File.Exists(path)) + versions[version] = new[] { new VisualStudioPath(DeriveVisualStudioPath(key)) }; + } + } + catch + { + // This can happen with a registry lookup failure + } + } + + GetInstalledVisualStudios(VisualStudioVersion.VisualStudio2017, versions); + GetInstalledVisualStudios(VisualStudioVersion.VisualStudio2019, versions); + } + + return versions; + } + + private static void GetInstalledVisualStudios(VisualStudioVersion vsVersion, Dictionary versions) + { + var requiredWorkloads = new[] { "Microsoft.VisualStudio.Workload.ManagedGame" }; + var raw = VisualStudioUtil.FindVisualStudioDevEnvPaths((int)vsVersion, requiredWorkloads); + + var visualStudioPaths = VisualStudioUtil.ParseRawDevEnvPaths(raw) + .Where(vs => !requiredWorkloads.Except(vs.WorkloadsAndComponents).Any()) // All required workloads must be present + .Select(vs => new VisualStudioPath(vs.DevEnvPath, vs.Edition)) + .ToArray(); + + if (visualStudioPaths.Length != 0) + versions[vsVersion] = visualStudioPaths; + } + + static string GetRegistryValue(string path, string key) + { + try + { + return Microsoft.Win32.Registry.GetValue(path, key, null) as string; + } + catch (Exception) + { + return ""; + } + } + + /// + /// Derives the Visual Studio installation path from the debugger path + /// + /// + /// The Visual Studio installation path (to devenv.exe) + /// + /// + /// The debugger path from the windows registry + /// + private static string DeriveVisualStudioPath(string debuggerPath) + { + string startSentinel = DeriveProgramFilesSentinel(); + string endSentinel = "Common7"; + bool started = false; + string[] tokens = debuggerPath.Split(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries); + + string path = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); + + // Walk directories in debugger path, chop out "Program Files\INSTALLATION\PATH\HERE\Common7" + foreach (var token in tokens) + { + if (!started && string.Equals(startSentinel, token, StringComparison.OrdinalIgnoreCase)) + { + started = true; + continue; + } + if (started) + { + path = Path.Combine(path, token); + if (string.Equals(endSentinel, token, StringComparison.OrdinalIgnoreCase)) + break; + } + } + + return UnityEditor.Utils.Paths.Combine(path, "IDE", "devenv.exe"); + } + + /// + /// Derives the program files sentinel for grabbing the VS installation path. + /// + /// + /// From a path like 'c:\Archivos de programa (x86)', returns 'Archivos de programa' + /// + private static string DeriveProgramFilesSentinel() + { + string path = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + .Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + .LastOrDefault(); + + if (!string.IsNullOrEmpty(path)) + { + // This needs to be the "real" Program Files regardless of 64bitness + int index = path.LastIndexOf("(x86)"); + if (0 <= index) + path = path.Remove(index); + return path.TrimEnd(); + } + + return "Program Files"; + } + + /// + /// Checks whether two paths are equivalent + /// + /// + /// Whether the paths are equivalent + /// + /// + /// A path + /// + /// + /// Another path + /// + private static bool PathsAreEquivalent(string aPath, string zPath) + { + if (aPath == null && zPath == null) + return true; + if (string.IsNullOrEmpty(aPath) || string.IsNullOrEmpty(zPath)) + return false; + + aPath = Path.GetFullPath(aPath); + zPath = Path.GetFullPath(zPath); + + StringComparison comparison = StringComparison.OrdinalIgnoreCase; + if (!(SolutionSynchronizationSettings.IsOSX || SolutionSynchronizationSettings.IsWindows)) + comparison = StringComparison.Ordinal; // Linux + + aPath = aPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); + zPath = zPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); + + return string.Equals(aPath, zPath, comparison); + } + + internal static bool CheckVisualStudioVersion(int major, int minor, int build) + { + int haveMinor = -1; + int haveBuild = -1; + + switch (major) + { + case 11: // Visual Studio 2012, getting it's version is different from others + { + // we'll grab version from (replace 11.0 with highest found 11.*): + // HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\DevDiv\vc\Servicing\11.0\RuntimeDebug\Version + Microsoft.Win32.RegistryKey servicing = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Wow6432Node\Microsoft\DevDiv\vc\Servicing"); + if (servicing == null) return false; + foreach (string name in servicing.GetSubKeyNames()) + { + if (name.StartsWith("11.") && name.Length > 3) + try + { + int foundMinor = Convert.ToInt32(name.Substring(3)); + if (foundMinor > haveMinor) + haveMinor = foundMinor; + } + catch (System.Exception) + {} + } + if (haveMinor < 0) return false; + Microsoft.Win32.RegistryKey key = servicing.OpenSubKey(string.Format(@"11.{0}\RuntimeDebug", haveMinor)); + if (key == null) return false; + string value = key.GetValue("Version", null) as string; + if (value == null) return false; + string[] components = value.Split('.'); + if (components == null || components.Length < 3) return false; + try + { + haveBuild = Convert.ToInt32(components[2]); + } + catch (System.Exception) + { + return false; + } + } + break; + default: + return false; + } + + return haveMinor > minor || (haveMinor == minor && haveBuild >= build); + } + } +} diff --git a/Editor/Mono/TypeSystem/UnityType.cs b/Editor/Mono/TypeSystem/UnityType.cs index ffbc649197..cf3ec1472a 100644 --- a/Editor/Mono/TypeSystem/UnityType.cs +++ b/Editor/Mono/TypeSystem/UnityType.cs @@ -19,6 +19,7 @@ enum UnityTypeFlags EditorOnly = 1 << 2 } + [System.Diagnostics.DebuggerDisplay("{module}:{name}")] sealed partial class UnityType { public string name { get; private set; } diff --git a/Editor/Mono/UIElements/Controls/BindingExtensions.cs b/Editor/Mono/UIElements/Controls/BindingExtensions.cs index 0c1f57fa0c..e093dfba31 100644 --- a/Editor/Mono/UIElements/Controls/BindingExtensions.cs +++ b/Editor/Mono/UIElements/Controls/BindingExtensions.cs @@ -310,12 +310,6 @@ internal static bool ValueEquals(TValue value, SerializedProperty p, Fun return EqualityComparer.Default.Equals(value, propVal); } - internal static bool OneWayStringValueEquals(string value, SerializedProperty p, Func propertyReadFunc) - { - var propVal = propertyReadFunc(p); - return String.CompareOrdinal(value, propVal) == 0; - } - internal static bool ValueEquals(string value, SerializedProperty p, Func propertyReadFunc) { if (p.propertyType == SerializedPropertyType.Enum) @@ -391,14 +385,6 @@ private static void CreateEnumBindingObject(VisualElement element, SerializedObj } } - private static void OneWayStringBind(VisualElement element, SerializedObjectUpdateWrapper objWrapper, SerializedProperty prop, - Func propertyReadFunc) - { - Func readToString = (SerializedProperty p) => $"{propertyReadFunc(p)}"; - - DefaultBind(element, objWrapper, prop, readToString, (p, s) => {}, OneWayStringValueEquals); - } - private static bool BindListView(ListView listView, SerializedObjectUpdateWrapper objWrapper, SerializedProperty prop) { // This should be done elsewhere. That's what the SerializedPropertyBindEvent are for. diff --git a/Editor/Mono/UIElements/Controls/CurveField.cs b/Editor/Mono/UIElements/Controls/CurveField.cs index 261e1d7d4c..512f083bef 100644 --- a/Editor/Mono/UIElements/Controls/CurveField.cs +++ b/Editor/Mono/UIElements/Controls/CurveField.cs @@ -35,6 +35,7 @@ private Color curveColor private bool m_ValueNull; private bool m_TextureDirty; + private Texture2D m_Texture; // The curve rasterized in a texture public enum RenderMode { @@ -146,17 +147,17 @@ public CurveField(string label) RegisterCallback(OnCustomStyleResolved); - generateVisualContent += OnGenerateVisualContent; + visualInput.generateVisualContent += OnGenerateVisualContent; } void OnDetach() { if (m_Mesh != null) Object.DestroyImmediate(m_Mesh); - if (visualInput.style.backgroundImage.value.texture != null) - Object.DestroyImmediate(visualInput.style.backgroundImage.value.texture); + if (m_Texture != null) + Object.DestroyImmediate(m_Texture); m_Mesh = null; - visualInput.style.backgroundImage = new Background(null); + m_Texture = null; m_TextureDirty = true; } @@ -182,8 +183,7 @@ public override void SetValueWithoutNotify(AnimationCurve newValue) CurveEditorWindow.instance.Repaint(); } - IncrementVersion(VersionChangeType.Repaint); - + visualInput.IncrementVersion(VersionChangeType.Repaint); m_Content?.IncrementVersion(VersionChangeType.Repaint); } @@ -425,8 +425,7 @@ void SetupMeshRepaint() if (m_TextureDirty || m_Mesh == null) { m_TextureDirty = false; - visualInput.style.backgroundImage = new Background(null); - + m_Texture = null; FillCurveData(); } m_Content.curveColor = curveColor; @@ -455,17 +454,17 @@ void SetupStandardRepaint() { if (!m_ValueNull) { - visualInput.style.backgroundImage = AnimationCurvePreviewCache.GenerateCurvePreview( + m_Texture = AnimationCurvePreviewCache.GenerateCurvePreview( previewWidth, previewHeight, rangeRect, rawValue, curveColor, - visualInput.computedStyle.backgroundImage.value.texture); + m_Texture); } else { - visualInput.style.backgroundImage = null; + m_Texture = null; } } } @@ -481,6 +480,12 @@ private void OnGenerateVisualContent(MeshGenerationContext mgc) else { SetupStandardRepaint(); + if (m_Texture != null) + { + var rectParams = MeshGenerationContextUtils.RectangleParams.MakeTextured( + new Rect(0, 0, m_Texture.width, m_Texture.height), new Rect(0, 0, 1, 1), m_Texture, ScaleMode.StretchToFill, panel.contextType); + MeshGenerationContextUtils.Rectangle(mgc, rectParams); + } } } diff --git a/Editor/Mono/UIElements/Controls/DoubleField.cs b/Editor/Mono/UIElements/Controls/DoubleField.cs index cb47b7e08d..6f9158dd6b 100644 --- a/Editor/Mono/UIElements/Controls/DoubleField.cs +++ b/Editor/Mono/UIElements/Controls/DoubleField.cs @@ -15,7 +15,7 @@ public class DoubleField : TextValueField DoubleInput doubleInput => (DoubleInput)textInputBase; public new class UxmlFactory : UxmlFactory {} - public new class UxmlTraits : BaseFieldTraits {} + public new class UxmlTraits : TextValueFieldTraits {} protected override string ValueToString(double v) { diff --git a/Editor/Mono/UIElements/Controls/FloatField.cs b/Editor/Mono/UIElements/Controls/FloatField.cs index 9da4507103..9e292d9ae3 100644 --- a/Editor/Mono/UIElements/Controls/FloatField.cs +++ b/Editor/Mono/UIElements/Controls/FloatField.cs @@ -14,7 +14,7 @@ public class FloatField : TextValueField FloatInput floatInput => (FloatInput)textInputBase; public new class UxmlFactory : UxmlFactory {} - public new class UxmlTraits : BaseFieldTraits {} + public new class UxmlTraits : TextValueFieldTraits {} protected override string ValueToString(float v) { diff --git a/Editor/Mono/UIElements/Controls/GradientField.cs b/Editor/Mono/UIElements/Controls/GradientField.cs index ebf0bac92e..b90823dbf4 100644 --- a/Editor/Mono/UIElements/Controls/GradientField.cs +++ b/Editor/Mono/UIElements/Controls/GradientField.cs @@ -126,7 +126,7 @@ void OnDetach() if (style.backgroundImage.value.texture != null) { Object.DestroyImmediate(style.backgroundImage.value.texture); - style.backgroundImage = new Background(null); + style.backgroundImage = new Background(); } } @@ -151,7 +151,7 @@ void UpdateGradientTexture() { if (m_ValueNull) { - visualInput.style.backgroundImage = new Background(null); + visualInput.style.backgroundImage = new Background(); } else { diff --git a/Editor/Mono/UIElements/Controls/IntegerField.cs b/Editor/Mono/UIElements/Controls/IntegerField.cs index e533d62b99..ed1807e5f9 100644 --- a/Editor/Mono/UIElements/Controls/IntegerField.cs +++ b/Editor/Mono/UIElements/Controls/IntegerField.cs @@ -15,7 +15,7 @@ public class IntegerField : TextValueField IntegerInput integerInput => (IntegerInput)textInputBase; public new class UxmlFactory : UxmlFactory {} - public new class UxmlTraits : BaseFieldTraits {} + public new class UxmlTraits : TextValueFieldTraits {} protected override string ValueToString(int v) { diff --git a/Editor/Mono/UIElements/Controls/LongField.cs b/Editor/Mono/UIElements/Controls/LongField.cs index 17e51a818f..b2401540dc 100644 --- a/Editor/Mono/UIElements/Controls/LongField.cs +++ b/Editor/Mono/UIElements/Controls/LongField.cs @@ -15,7 +15,7 @@ public class LongField : TextValueField LongInput longInput => (LongInput)textInputBase; public new class UxmlFactory : UxmlFactory {} - public new class UxmlTraits : BaseFieldTraits {} + public new class UxmlTraits : TextValueFieldTraits {} protected override string ValueToString(long v) { diff --git a/Editor/Mono/UIElements/Controls/TextValueField.cs b/Editor/Mono/UIElements/Controls/TextValueField.cs index 8b4a260ce1..66dd03064b 100644 --- a/Editor/Mono/UIElements/Controls/TextValueField.cs +++ b/Editor/Mono/UIElements/Controls/TextValueField.cs @@ -101,12 +101,6 @@ protected TextValueInput() internal bool m_UpdateTextFromValue; - void UpdateValueFromText() - { - var newValue = StringToValue(text); - textValueFieldParent.value = newValue; - } - internal override bool AcceptCharacter(char c) { return base.AcceptCharacter(c) && c != 0 && allowedCharacters.IndexOf(c) != -1; @@ -138,7 +132,10 @@ public void StopDragging() protected abstract string ValueToString(TValueType value); - protected abstract TValueType StringToValue(string str); + protected override TValueType StringToValue(string str) + { + return base.StringToValue(str); + } protected override void ExecuteDefaultActionAtTarget(EventBase evt) { @@ -155,12 +152,12 @@ protected override void ExecuteDefaultActionAtTarget(EventBase evt) // Here we should update the value, but it will be done when the blur event will be handled... parent.Focus(); } - else + else if (!isReadOnly) { hasChanged = true; } } - else if (evt.eventTypeId == ExecuteCommandEvent.TypeId()) + else if (!isReadOnly && evt.eventTypeId == ExecuteCommandEvent.TypeId()) { ExecuteCommandEvent commandEvt = evt as ExecuteCommandEvent; string cmdName = commandEvt.commandName; @@ -210,4 +207,21 @@ protected override void ExecuteDefaultAction(EventBase evt) } } } + + // Derive from BaseFieldTraits in order to not inherit from TextInputBaseField UXML attributes. + public class TextValueFieldTraits : BaseFieldTraits + where TValueUxmlAttributeType : TypedUxmlAttributeDescription, new() + { + UxmlBoolAttributeDescription m_IsReadOnly = new UxmlBoolAttributeDescription { name = "readonly" }; + + public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) + { + base.Init(ve, bag, cc); + var field = (TextInputBaseField)ve; + if (field != null) + { + field.isReadOnly = m_IsReadOnly.GetValueFromBag(bag, cc); + } + } + } } diff --git a/Editor/Mono/UIElements/FieldMouseDragger.cs b/Editor/Mono/UIElements/FieldMouseDragger.cs index cf4ed61ebb..ceb4b38674 100644 --- a/Editor/Mono/UIElements/FieldMouseDragger.cs +++ b/Editor/Mono/UIElements/FieldMouseDragger.cs @@ -83,7 +83,8 @@ void UpdateValueOnMouseUp(MouseUpEvent evt) if (dragging) { dragging = false; - MouseCaptureController.ReleaseMouse(); + IPanel panel = (evt.target as VisualElement)?.panel; + panel.ReleasePointer(PointerId.mousePointerId); EditorGUIUtility.SetWantsMouseJumping(0); m_DrivenField.StopDragging(); } @@ -96,7 +97,8 @@ void UpdateValueOnKeyDown(KeyDownEvent evt) dragging = false; m_DrivenField.value = startValue; m_DrivenField.StopDragging(); - MouseCaptureController.ReleaseMouse(); + IPanel panel = (evt.target as VisualElement)?.panel; + panel.ReleasePointer(PointerId.mousePointerId); EditorGUIUtility.SetWantsMouseJumping(0); } } diff --git a/Editor/Mono/UIElements/Renderer/EditorAtlasMonitor.cs b/Editor/Mono/UIElements/Renderer/EditorAtlasMonitor.cs index 5a10d537b1..de10c22f08 100644 --- a/Editor/Mono/UIElements/Renderer/EditorAtlasMonitor.cs +++ b/Editor/Mono/UIElements/Renderer/EditorAtlasMonitor.cs @@ -6,41 +6,30 @@ using UnityEngine; using UnityEngine.Assertions; using UnityEngine.UIElements; +using UnityEngine.UIElements.UIR; namespace UnityEditor.UIElements { [InitializeOnLoad] - internal class EditorAtlasMonitor : IAtlasMonitor + internal static class EditorAtlasMonitor { static EditorAtlasMonitor() { - s_Monitors = new Dictionary(); - var createdAtlasManagerInstances = UIRAtlasManager.Instances(); - for (int i = 0; i != createdAtlasManagerInstances.Count; ++i) - { - OnAtlasManagerCreated(createdAtlasManagerInstances[i]); - } - UIRAtlasManager.atlasManagerCreated += OnAtlasManagerCreated; - UIRAtlasManager.atlasManagerDisposed += OnAtlasManagerDisposed; - } - - private static Dictionary s_Monitors; - - private static void OnAtlasManagerCreated(UIRAtlasManager atlasManager) - { - Assert.IsFalse(s_Monitors.ContainsKey(atlasManager)); - s_Monitors.Add(atlasManager, new EditorAtlasMonitor(atlasManager)); - } - - private static void OnAtlasManagerDisposed(UIRAtlasManager atlasManager) - { - bool removedMonitor = s_Monitors.Remove(atlasManager); - Assert.IsTrue(removedMonitor); + RenderChain.OnPreRender += OnPreRender; } - public EditorAtlasMonitor(UIRAtlasManager atlasManager) + public static void OnPreRender() { - atlasManager.AddMonitor(this); + bool colorSpaceChanged = CheckForColorSpaceChange(); + bool importedTextureChanged = CheckForImportedTextures(); + bool importedVectorImageChanged = CheckForImportedVectorImages(); + if (colorSpaceChanged || importedTextureChanged) + { + UIRAtlasManager.MarkAllForReset(); + VectorImageManager.MarkAllForReset(); + } + else if (colorSpaceChanged || importedVectorImageChanged) + VectorImageManager.MarkAllForReset(); } private class TexturePostProcessor : UnityEditor.AssetPostprocessor @@ -50,21 +39,22 @@ public void OnPostprocessTexture(Texture2D texture) ++importedTexturesCount; } + static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) + { + foreach (var assetPath in importedAssets) + if (System.IO.Path.GetExtension(assetPath) == ".svg") + ++importedVectorImagesCount; + } + public static int importedTexturesCount; + public static int importedVectorImagesCount; } - private ColorSpace m_LastColorSpace; - private int m_LastImportedTexturesCount; + private static ColorSpace m_LastColorSpace; + private static int m_LastImportedTexturesCount; + private static int m_LastImportedVectorImagesCount; - public bool RequiresReset() - { - bool colorSpaceChanged = CheckForColorSpaceChange(); - bool importedTextures = CheckForImportedTextures(); - - return colorSpaceChanged || importedTextures; - } - - private bool CheckForColorSpaceChange() + private static bool CheckForColorSpaceChange() { ColorSpace activeColorSpace = QualitySettings.activeColorSpace; if (m_LastColorSpace == activeColorSpace) @@ -74,7 +64,7 @@ private bool CheckForColorSpaceChange() return true; } - private bool CheckForImportedTextures() + private static bool CheckForImportedTextures() { int importedTexturesCount = TexturePostProcessor.importedTexturesCount; if (m_LastImportedTexturesCount == importedTexturesCount) @@ -84,5 +74,16 @@ private bool CheckForImportedTextures() return true; } + + private static bool CheckForImportedVectorImages() + { + int importedVectorImagesCount = TexturePostProcessor.importedVectorImagesCount; + if (m_LastImportedVectorImagesCount == importedVectorImagesCount) + return false; + + m_LastImportedVectorImagesCount = importedVectorImagesCount; + + return true; + } } } diff --git a/Editor/Mono/UIElements/UIElementsEditorWindowCreator/UssTemplateCreator.cs b/Editor/Mono/UIElements/UIElementsEditorWindowCreator/UssTemplateCreator.cs index 727595da38..5ee2a30aab 100644 --- a/Editor/Mono/UIElements/UIElementsEditorWindowCreator/UssTemplateCreator.cs +++ b/Editor/Mono/UIElements/UIElementsEditorWindowCreator/UssTemplateCreator.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.IO; using UnityEngine; using UnityEngine.UIElements; diff --git a/Editor/Mono/UIElements/UIElementsViewImporter.cs b/Editor/Mono/UIElements/UIElementsViewImporter.cs index 6ebb3304b4..32dfc09606 100644 --- a/Editor/Mono/UIElements/UIElementsViewImporter.cs +++ b/Editor/Mono/UIElements/UIElementsViewImporter.cs @@ -22,6 +22,7 @@ namespace UnityEditor.UIElements { // Make sure UXML is imported after assets than can be addressed in USS [ScriptedImporter(version: 6, ext: "uxml", importQueueOffset: 1100)] + [ExcludeFromPreset] internal class UIElementsViewImporter : ScriptedImporter { // Parses the XML file to figure out dependencies to other UXML/USS files diff --git a/Editor/Mono/UIElements/VisualTreeAssetEditor.cs b/Editor/Mono/UIElements/VisualTreeAssetEditor.cs index dc80814ee9..c32e4fcb7b 100644 --- a/Editor/Mono/UIElements/VisualTreeAssetEditor.cs +++ b/Editor/Mono/UIElements/VisualTreeAssetEditor.cs @@ -67,7 +67,7 @@ public void Render(VisualTreeAsset vta, Rect r, GUIStyle background) if (m_Panel == null) { - m_Panel = UIElementsUtility.FindOrCreatePanel(m_LastTree, ContextType.Editor); + m_Panel = UIElementsUtility.FindOrCreateEditorPanel(m_LastTree); var visualTree = m_Panel.visualTree; visualTree.pseudoStates |= PseudoStates.Root; UIElementsEditorUtility.AddDefaultEditorStyleSheets(visualTree); diff --git a/Editor/Mono/UnityConnect/UnityConnect.bindings.cs b/Editor/Mono/UnityConnect/UnityConnect.bindings.cs index 49476efd2f..db28653977 100644 --- a/Editor/Mono/UnityConnect/UnityConnect.bindings.cs +++ b/Editor/Mono/UnityConnect/UnityConnect.bindings.cs @@ -24,7 +24,10 @@ internal enum CloudConfigUrl CloudPortal = 7, CloudPerfEvents = 8, CloudAdsDashboard = 9, - CloudServicesDashboard = 10 + CloudServicesDashboard = 10, + CloudPackagesApi = 11, + CloudPackagesKey = 12, + CloudAssetStoreUrl = 13 } //*undocumented* @@ -179,7 +182,7 @@ public static void GetAuthorizationCodeAsync(string clientId, Action 0) - pathSearch.Add(item.Asset.path.ToLower(), item); - else if (item.Change != null) - { - pathSearch.Add(c_changeKeyPrefix + item.Change.id.ToString(), item); - return; - } - ListItem en = item.FirstChild; - while (en != null) - { - PathSearchUpdate(en); - en = en.Next; - } - } - // Is the item selected? internal bool IsSelected(ListItem item) { @@ -1144,13 +1126,18 @@ public void SelectedAdd(ListItem item) name = name.EndsWith(c_metaSuffix) ? name.Substring(0, name.Length - 5) : name; int itemID = AssetDatabase.GetMainAssetInstanceID(name.TrimEnd('/')); + + int[] newSel = new int[arrayLen + 1]; + + //asset is in current project - the correct folder is opened + //asset is in another project - current project root folder is opened if (itemID != 0) { - int[] newSel = new int[arrayLen + 1]; newSel[arrayLen] = itemID; - Array.Copy(sel, newSel, arrayLen); - Selection.instanceIDs = newSel; } + + Array.Copy(sel, newSel, arrayLen); + Selection.instanceIDs = newSel; } void SelectedRemove(ListItem item) diff --git a/Editor/Mono/VersionControl/UI/VCOverlay.cs b/Editor/Mono/VersionControl/UI/VCOverlay.cs index 8758f4a3f9..5a58412d09 100644 --- a/Editor/Mono/VersionControl/UI/VCOverlay.cs +++ b/Editor/Mono/VersionControl/UI/VCOverlay.cs @@ -89,6 +89,9 @@ static void DrawOverlay(Asset.States state, Rect iconRect) static void DrawOverlays(Asset asset, Asset metaAsset, Rect itemRect) { + if (!EditorUserSettings.overlayIcons) + return; + CreateStaticResources(); float iconWidth = 16; float offsetX = 1f; // offset to compensate that icons are 16x16 with 8x8 content diff --git a/Editor/Mono/VersionControl/VCProvider.bindings.cs b/Editor/Mono/VersionControl/VCProvider.bindings.cs index 636eef5bd5..554aa6efa6 100644 --- a/Editor/Mono/VersionControl/VCProvider.bindings.cs +++ b/Editor/Mono/VersionControl/VCProvider.bindings.cs @@ -300,5 +300,13 @@ internal static extern CustomCommand[] customCommands [NativeThrows] [FreeFunction("VersionControlBindings::VCProvider::Internal_ConsolidateAssetList")] private static extern Asset[] Internal_ConsolidateAssetList(Asset[] assets, CheckoutMode mode); + + [StaticAccessor("VCProvider", StaticAccessorType.DoubleColon)] + [NativeMethod("ShouldAddMetaFile")] + static internal extern bool PathHasMetaFile(string path); + + [StaticAccessor("VCProvider", StaticAccessorType.DoubleColon)] + [NativeMethod("ShouldPathBeVersioned")] + static internal extern bool PathIsVersioned(string path); } } diff --git a/Editor/Mono/VisualStudioIntegration/SolutionSynchronizationSettings.cs b/Editor/Mono/VisualStudioIntegration/SolutionSynchronizationSettings.cs new file mode 100644 index 0000000000..38e4c68fc5 --- /dev/null +++ b/Editor/Mono/VisualStudioIntegration/SolutionSynchronizationSettings.cs @@ -0,0 +1,228 @@ +// 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 System.Security; +using System.Security.Cryptography; +using System.Xml; +using System.Text; +using System.Text.RegularExpressions; +namespace UnityEditor.VisualStudioIntegration +{ + interface ISolutionSynchronizationSettings + { + int VisualStudioVersion { get; } + string SolutionTemplate { get; } + string SolutionProjectEntryTemplate { get; } + string SolutionProjectConfigurationTemplate { get; } + string EditorAssemblyPath { get; } + string EngineAssemblyPath { get; } + string MonoLibFolder { get; } + string[] Defines { get; } + string GetProjectHeaderTemplate(ScriptingLanguage language); + string GetProjectFooterTemplate(ScriptingLanguage language); + } + + internal class DefaultSolutionSynchronizationSettings : ISolutionSynchronizationSettings + { + public virtual int VisualStudioVersion + { + get { return 9; } + } + + public virtual string SolutionTemplate + { + get + { + return string.Join("\r\n", new[] + { + @"", + @"Microsoft Visual Studio Solution File, Format Version {0}", + @"# Visual Studio {1}", + @"{2}", + @"Global", + @" GlobalSection(SolutionConfigurationPlatforms) = preSolution", + @" Debug|Any CPU = Debug|Any CPU", + @" Release|Any CPU = Release|Any CPU", + @" EndGlobalSection", + @" GlobalSection(ProjectConfigurationPlatforms) = postSolution", + @"{3}", + @" EndGlobalSection", + @" GlobalSection(SolutionProperties) = preSolution", + @" HideSolutionNode = FALSE", + @" EndGlobalSection", + @"EndGlobal", + @"" + }).Replace(" ", "\t"); + } + } + + public virtual string SolutionProjectEntryTemplate + { + get + { + return string.Join("\r\n", new[] + { + @"Project(""{{{0}}}"") = ""{1}"", ""{2}"", ""{{{3}}}""", + @"EndProject" + }).Replace(" ", "\t"); + } + } + + public virtual string SolutionProjectConfigurationTemplate + { + get + { + return string.Join("\r\n", new[] + { + @" {{{0}}}.Debug|Any CPU.ActiveCfg = Debug|Any CPU", + @" {{{0}}}.Debug|Any CPU.Build.0 = Debug|Any CPU", + @" {{{0}}}.Release|Any CPU.ActiveCfg = Release|Any CPU", + @" {{{0}}}.Release|Any CPU.Build.0 = Release|Any CPU" + }).Replace(" ", "\t"); + } + } + + public virtual string GetProjectHeaderTemplate(ScriptingLanguage language) + { + var header = new[] + { + @"", + @"", + @" ", + @" {10}", + @" {13}", + @" {14}", + @" ", + @" ", + @" Debug", + @" AnyCPU", + @" {1}", + @" 2.0", + @" {8}", + @" {{{2}}}", + @" Library", + @" Properties", + @" {7}", + @" {9}", + @" 512", + @" {11}", + @" ", + @" ", + @" true", + @" full", + @" false", + @" Temp\bin\Debug\", + @" {5}", + @" prompt", + @" 4", + @" 0169", + @" {12}", + @" ", + @" ", + @" pdbonly", + @" true", + @" Temp\bin\Release\", + @" prompt", + @" 4", + @" 0169", + @" {12}", + @" ", + }; + + var forceExplicitReferences = new string[] + { + @" ", + @" true", + @" true", + @" false", + @" false", + @" false", + @" ", + }; + + var itemGroupStart = new[] + { + @" ", + }; + + var systemReferences = new string[] + { + @" ", + @" ", + @" ", + @" ", + @" ", + }; + + var footer = new string[] + { + @" ", + @" {3}", + @" ", + @" ", + @" {4}", + @" ", + @" ", + @" ", + @"" + }; + + string[] text; + + if (language == ScriptingLanguage.CSharp) + text = header.Concat(forceExplicitReferences).Concat(itemGroupStart).Concat(footer).ToArray(); + else + text = header.Concat(itemGroupStart).Concat(systemReferences).Concat(footer).ToArray(); + + return string.Join("\r\n", text); + } + + public virtual string GetProjectFooterTemplate(ScriptingLanguage language) + { + return string.Join("\r\n", new[] + { + @" ", + @" ", + @" ", + @"", + @"" + }); + } + + public virtual string EditorAssemblyPath + { + get { return "/Managed/UnityEditor.dll"; } + } + + public virtual string EngineAssemblyPath + { + get { return "/Managed/UnityEngine.dll"; } + } + + public virtual string MonoLibFolder + { + get { return FrameworksPath() + "/Mono/lib/mono/unity/"; } + } + + public virtual string[] Defines + { + get { return new string[0]; } + } + + protected virtual string FrameworksPath() + { + return string.Empty; + } + } +} diff --git a/Editor/Mono/VisualStudioIntegration/SolutionSynchronizer.cs b/Editor/Mono/VisualStudioIntegration/SolutionSynchronizer.cs new file mode 100644 index 0000000000..14ccd0bb9a --- /dev/null +++ b/Editor/Mono/VisualStudioIntegration/SolutionSynchronizer.cs @@ -0,0 +1,784 @@ +// 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 System.Security; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; +using UnityEditor.Scripting; +using UnityEditor.Scripting.ScriptCompilation; +using UnityEditor.Utils; +using UnityEditorInternal; +using UnityEditor.Scripting.Compilers; +using UnityEngine.Profiling; + +using UnityEditor.Compilation; +using UnityEditor.Modules; +using UnityEngine; +using UnityEditor.PackageManager; + +namespace UnityEditor.VisualStudioIntegration +{ + enum ScriptingLanguage + { + None, + Boo, + CSharp, + UnityScript, + } + + interface IAssemblyNameProvider + { + string GetAssemblyNameFromScriptPath(string path); + IEnumerable GetAllScriptAssemblies(Func shouldFileBePartOfSolution, string projectDirectory); + IEnumerable GetAllAssetPaths(); + } + + class AssemblyNameProvider : IAssemblyNameProvider + { + public string GetAssemblyNameFromScriptPath(string path) + { + return CompilationPipeline.GetAssemblyNameFromScriptPath(path); + } + + public IEnumerable GetAllScriptAssemblies(Func shouldFileBePartOfSolution, string projectDirectory) + { + 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(); + } + + public IEnumerable GetAllAssetPaths() + { + return AssetDatabase.GetAllAssetPaths(); + } + } + + class SolutionSynchronizer + { + enum Mode + { + UnityScriptAsUnityProj, + UnityScriptAsPrecompiledAssembly + } + + public static readonly ISolutionSynchronizationSettings DefaultSynchronizationSettings = + new DefaultSolutionSynchronizationSettings(); + + static readonly string WindowsNewline = "\r\n"; + + /// + /// Map source extensions to ScriptingLanguages + /// + static internal readonly Dictionary BuiltinSupportedExtensions = new Dictionary + { + {"cs", ScriptingLanguage.CSharp}, + {"uxml", ScriptingLanguage.None}, + {"uss", ScriptingLanguage.None}, + {"shader", ScriptingLanguage.None}, + {"compute", ScriptingLanguage.None}, + {"cginc", ScriptingLanguage.None}, + {"hlsl", ScriptingLanguage.None}, + {"glslinc", ScriptingLanguage.None}, + {"template", ScriptingLanguage.None}, + {"raytrace", ScriptingLanguage.None}, + }; + + private static readonly string[] reimportSyncExtensions = new[] { ".dll", ".asmdef" }; + + string[] ProjectSupportedExtensions = new string[0]; + + /// + /// Map ScriptingLanguages to project extensions + /// + static readonly Dictionary ProjectExtensions = new Dictionary + { + { ScriptingLanguage.Boo, ".booproj" }, + { ScriptingLanguage.CSharp, ".csproj" }, + { ScriptingLanguage.UnityScript, ".unityproj" }, + { ScriptingLanguage.None, ".csproj" }, + }; + + public static readonly string MSBuildNamespaceUri = "http://schemas.microsoft.com/developer/msbuild/2003"; + + private readonly string _projectDirectory; + private readonly ISolutionSynchronizationSettings _settings; + private readonly string _projectName; + readonly IAssemblyNameProvider m_assemblyNameProvider; + bool m_ShouldGenerateAll; + + public SolutionSynchronizer(string projectDirectory, ISolutionSynchronizationSettings settings, IAssemblyNameProvider assemblyNameProvider) + { + _projectDirectory = projectDirectory.ConvertSeparatorsToUnity(); + _settings = settings; + _projectName = Path.GetFileName(_projectDirectory); + m_assemblyNameProvider = assemblyNameProvider; + } + + public SolutionSynchronizer(string projectDirectory, ISolutionSynchronizationSettings settings) : this(projectDirectory, settings, new AssemblyNameProvider()) + { + } + + public SolutionSynchronizer(string projectDirectory) : this(projectDirectory, DefaultSynchronizationSettings) + { + } + + private void SetupProjectSupportedExtensions() + { + ProjectSupportedExtensions = EditorSettings.projectGenerationUserExtensions; + } + + public bool ShouldFileBePartOfSolution(string file) + { + string extension = Path.GetExtension(file); + + // Exclude files coming from packages except if they are internalized. + if (!m_ShouldGenerateAll && IsNonInternalizedPackagePath(file)) + { + return false; + } + + // Dll's are not scripts but still need to be included.. + if (extension == ".dll") + return true; + + if (file.ToLower().EndsWith(".asmdef")) + return true; + + return IsSupportedExtension(extension); + } + + private bool IsSupportedExtension(string extension) + { + extension = extension.TrimStart('.'); + if (BuiltinSupportedExtensions.ContainsKey(extension)) + return true; + if (ProjectSupportedExtensions.Contains(extension)) + return true; + return false; + } + + private static ScriptingLanguage ScriptingLanguageFor(MonoIsland island) + { + return ScriptingLanguageFor(island.GetExtensionOfSourceFiles()); + } + + private static ScriptingLanguage ScriptingLanguageFor(string extension) + { + ScriptingLanguage result; + if (BuiltinSupportedExtensions.TryGetValue(extension.TrimStart('.'), out result)) + return result; + + return ScriptingLanguage.None; + } + + public bool ProjectExists(MonoIsland island) + { + return File.Exists(ProjectFile(island)); + } + + public bool SolutionExists() + { + return File.Exists(SolutionFile()); + } + + private static void DumpIsland(MonoIsland island) + { + Console.WriteLine("{0} ({1})", island._output, island._api_compatibility_level); + Console.WriteLine("Files: "); + Console.WriteLine(string.Join("\n", island._files)); + Console.WriteLine("References: "); + Console.WriteLine(string.Join("\n", island._references)); + Console.WriteLine(""); + } + + /// + /// Syncs the scripting solution if any affected files are relevant. + /// + /// + /// Whether the solution was synced. + /// + /// + /// A set of files whose status has changed + /// + /// + /// A set of files that got reimported + /// + public bool SyncIfNeeded(IEnumerable affectedFiles, IEnumerable reimportedFiles) + { + SetupProjectSupportedExtensions(); + + // Don't sync if we haven't synced before + if (SolutionExists() && (affectedFiles.Any(ShouldFileBePartOfSolution) || reimportedFiles.Any(ShouldSyncOnReimportedAsset))) + { + Sync(); + return true; + } + + return false; + } + + private bool ShouldSyncOnReimportedAsset(string asset) + { + return reimportSyncExtensions.Contains(new FileInfo(asset).Extension); + } + + public void Sync() + { + Profiler.BeginSample("SolutionSynchronizerSync"); + // Do not sync solution until all Unity extensions are registered and initialized. + // Otherwise Unity might emit errors when VSTU tries to generate the solution and + // get all managed extensions, which not yet initialized. + if (!InternalEditorUtility.IsUnityExtensionsInitialized()) + { + Profiler.EndSample(); + return; + } + + SetupProjectSupportedExtensions(); + + bool externalCodeAlreadyGeneratedProjects = AssetPostprocessingInternal.OnPreGeneratingCSProjectFiles(); + + if (!externalCodeAlreadyGeneratedProjects) + { + #pragma warning disable 618 + var scriptEditor = ScriptEditorUtility.GetScriptEditorFromPreferences(); + GenerateAndWriteSolutionAndProjects(scriptEditor); + } + + AssetPostprocessingInternal.CallOnGeneratedCSProjectFiles(); + Profiler.EndSample(); + } + + internal void GenerateAndWriteSolutionAndProjects(ScriptEditorUtility.ScriptEditor scriptEditor) + { + Profiler.BeginSample("GenerateAndWriteSolutionAndProjects"); + + Profiler.BeginSample("SolutionSynchronizer.GetIslands"); + // Only synchronize islands that have associated source files and ones that we actually want in the project. + // This also filters out DLLs coming from .asmdef files in packages. + IEnumerable islands = m_assemblyNameProvider.GetAllScriptAssemblies(ShouldFileBePartOfSolution, _projectDirectory); + + Profiler.EndSample(); + + Profiler.BeginSample("GenerateAllAssetProjectParts.GetIslands"); + var allAssetProjectParts = GenerateAllAssetProjectParts(); + Profiler.EndSample(); + + var monoIslands = islands.ToList(); + + Profiler.BeginSample("SyncSolution"); + SyncSolution(monoIslands.ToList()); + Profiler.EndSample(); + + var allProjectIslands = RelevantIslandsForMode(monoIslands, ModeForCurrentExternalEditor()).ToList(); + + foreach (MonoIsland island in allProjectIslands) + { + Profiler.BeginSample("SyncProject"); + SyncProject(island, allAssetProjectParts, ParseResponseFileData(island), allProjectIslands); + Profiler.EndSample(); + } + + Profiler.EndSample(); + } + + IEnumerable ParseResponseFileData(MonoIsland island) + { + var systemReferenceDirectories = MonoLibraryHelpers.GetSystemReferenceDirectories(island._api_compatibility_level); + + Dictionary responseFilesData = island._responseFiles.ToDictionary(x => x, x => ScriptCompilerBase.ParseResponseFileFromFile( + x, + _projectDirectory, + systemReferenceDirectories + )); + + Dictionary responseFilesWithErrors = responseFilesData.Where(x => x.Value.Errors.Any()) + .ToDictionary(x => x.Key, x => x.Value); + + if (responseFilesWithErrors.Any()) + { + foreach (var error in responseFilesWithErrors) + foreach (var valueError in error.Value.Errors) + { + UnityEngine.Debug.LogErrorFormat("{0} Parse Error : {1}", error.Key, valueError); + } + } + + return responseFilesData.Select(x => x.Value); + } + + Dictionary GenerateAllAssetProjectParts() + { + Dictionary stringBuilders = new Dictionary(); + + foreach (string asset in m_assemblyNameProvider.GetAllAssetPaths()) + { + // Exclude files coming from packages except if they are internalized. + if (!m_ShouldGenerateAll && IsNonInternalizedPackagePath(asset)) + { + continue; + } + string extension = Path.GetExtension(asset); + if (IsSupportedExtension(extension) && ScriptingLanguage.None == ScriptingLanguageFor(extension)) + { + // Find assembly the asset belongs to by adding script extension and using compilation pipeline. + var assemblyName = m_assemblyNameProvider.GetAssemblyNameFromScriptPath(asset + ".cs"); + assemblyName = assemblyName ?? m_assemblyNameProvider.GetAssemblyNameFromScriptPath(asset + ".js"); + assemblyName = assemblyName ?? m_assemblyNameProvider.GetAssemblyNameFromScriptPath(asset + ".boo"); + + if (string.IsNullOrEmpty(assemblyName)) + { + continue; + } + + assemblyName = Utility.FileNameWithoutExtension(assemblyName); + + StringBuilder projectBuilder = null; + + if (!stringBuilders.TryGetValue(assemblyName, out projectBuilder)) + { + projectBuilder = new StringBuilder(); + stringBuilders[assemblyName] = projectBuilder; + } + + projectBuilder.Append(" ").Append(WindowsNewline); + } + } + + var result = new Dictionary(); + + foreach (var entry in stringBuilders) + result[entry.Key] = entry.Value.ToString(); + + return result; + } + + bool IsNonInternalizedPackagePath(string file) + { + if (UnityEditor.PackageManager.Folders.IsPackagedAssetPath(file)) + { + bool rootFolder, readOnly; + bool validPath = AssetDatabase.GetAssetFolderInfo(file, out rootFolder, out readOnly); + return (!validPath || readOnly); + } + return false; + } + + void SyncProject(MonoIsland island, + Dictionary allAssetsProjectParts, + IEnumerable responseFilesData, + List allProjectIslands) + { + SyncProjectFileIfNotChanged(ProjectFile(island), ProjectText(island, ModeForCurrentExternalEditor(), allAssetsProjectParts, responseFilesData, allProjectIslands)); + } + + static void SyncProjectFileIfNotChanged(string path, string newContents) + { + if (Path.GetExtension(path) == ".csproj") + { + newContents = AssetPostprocessingInternal.CallOnGeneratedCSProject(path, newContents); + } + + SyncFileIfNotChanged(path, newContents); + } + + static void SyncSolutionFileIfNotChanged(string path, string newContents) + { + newContents = AssetPostprocessingInternal.CallOnGeneratedSlnSolution(path, newContents); + + SyncFileIfNotChanged(path, newContents); + } + + static void LogDifference(string path, string currentContents, string newContents) + { + Console.WriteLine("[C# Project] Writing {0} because it has changed", path); + + var currentReader = new StringReader(currentContents); + var newReader = new StringReader(newContents); + + string currentLine = null; + string newLine = null; + int lineNumber = 1; + + do + { + currentLine = currentReader.ReadLine(); + newLine = newReader.ReadLine(); + + if (currentLine != null && newLine != null && currentLine != newLine) + { + Console.WriteLine("[C# Project] First difference on line {0}", lineNumber); + + Console.WriteLine("\n[C# Project] Current {0}:", path); + + for (int i = 0; + i < 5 && currentLine != null; + i++, currentLine = currentReader.ReadLine()) + { + Console.WriteLine("[C# Project] {0:D3}: {1}", lineNumber + i, currentLine); + } + + Console.WriteLine("\n[C# Project] New {0}:", path); + + for (int i = 0; + i < 5 && newLine != null; + i++, newLine = newReader.ReadLine()) + { + Console.WriteLine("[C# Project] {0:D3}: {1}", lineNumber + i, newLine); + } + + currentLine = null; + newLine = null; + } + + lineNumber++; + } + while (currentLine != null && newLine != null); + } + + private static void SyncFileIfNotChanged(string filename, string newContents) + { + if (File.Exists(filename)) + { + var currentContents = File.ReadAllText(filename); + + if (currentContents == newContents) + { + return; + } + + try + { + LogDifference(filename, currentContents, newContents); + } + catch (Exception exception) + { + Console.WriteLine("Failed to log difference of {0}\n{1}", + filename, exception); + } + } + + File.WriteAllText(filename, newContents, Encoding.UTF8); + } + + public static readonly Regex scriptReferenceExpression = new Regex( + @"^Library.ScriptAssemblies.(?(?.*)\.dll$)", + RegexOptions.Compiled | RegexOptions.IgnoreCase); + + static bool IsAdditionalInternalAssemblyReference(bool isBuildingEditorProject, string reference) + { + if (isBuildingEditorProject) + return Modules.ModuleUtils.GetAdditionalReferencesForEditorCsharpProject().Contains(reference); + return false; + } + + string ProjectText(MonoIsland island, + Mode mode, + Dictionary allAssetsProjectParts, + IEnumerable responseFilesData, + List allProjectIslands) + { + var projectBuilder = new StringBuilder(ProjectHeader(island, responseFilesData)); + var references = new List(); + var projectReferences = new List(); + Match match; + bool isBuildingEditorProject = island._editor; + + foreach (string file in island._files) + { + if (!ShouldFileBePartOfSolution(file)) + continue; + + var extension = Path.GetExtension(file).ToLower(); + var fullFile = EscapedRelativePathFor(file); + if (".dll" != extension) + { + var tagName = "Compile"; + projectBuilder.Append(" <").Append(tagName).Append(" Include=\"").Append(fullFile).Append("\" />").Append(WindowsNewline); + } + else + { + references.Add(fullFile); + } + } + + string additionalAssetsForProject; + var assemblyName = Utility.FileNameWithoutExtension(island._output); + + // Append additional non-script files that should be included in project generation. + if (allAssetsProjectParts.TryGetValue(assemblyName, out additionalAssetsForProject)) + projectBuilder.Append(additionalAssetsForProject); + + var allAdditionalReferenceFilenames = new List(); + var islandRefs = references.Union(island._references); + + foreach (string reference in islandRefs) + { + if (reference.EndsWith("/UnityEditor.dll", StringComparison.Ordinal) + || reference.EndsWith("/UnityEngine.dll", StringComparison.Ordinal) + || reference.EndsWith("\\UnityEditor.dll", StringComparison.Ordinal) + || reference.EndsWith("\\UnityEngine.dll", StringComparison.Ordinal)) + continue; + + match = scriptReferenceExpression.Match(reference); + if (match.Success) + { + var language = ScriptCompilers.GetLanguageFromExtension(island.GetExtensionOfSourceFiles()); + var targetLanguage = (ScriptingLanguage)Enum.Parse(typeof(ScriptingLanguage), language.GetLanguageName(), true); + if (mode == Mode.UnityScriptAsUnityProj || ScriptingLanguage.CSharp == targetLanguage) + { + // Add a reference to a project except if it's a reference to a script assembly + // that we are not generating a project for. This will be the case for assemblies + // coming from .assembly.json files in non-internalized packages. + var dllName = match.Groups["dllname"].Value; + if (allProjectIslands.Any(i => Path.GetFileName(i._output) == dllName)) + { + projectReferences.Add(match); + continue; + } + } + } + + string fullReference = Path.IsPathRooted(reference) ? reference : Path.Combine(_projectDirectory, reference); + if (!AssemblyHelper.IsManagedAssembly(fullReference)) + continue; + if (AssemblyHelper.IsInternalAssembly(fullReference)) + { + if (!IsAdditionalInternalAssemblyReference(isBuildingEditorProject, fullReference)) + continue; + var referenceName = Path.GetFileName(fullReference); + if (allAdditionalReferenceFilenames.Contains(referenceName)) + continue; + allAdditionalReferenceFilenames.Add(referenceName); + } + + AppendReference(fullReference, projectBuilder); + } + + var responseRefs = responseFilesData.SelectMany(x => x.FullPathReferences); + foreach (var reference in responseRefs) + { + AppendReference(reference, projectBuilder); + } + + if (0 < projectReferences.Count) + { + string referencedProject; + projectBuilder.AppendLine(" "); + projectBuilder.AppendLine(" "); + foreach (Match reference in projectReferences) + { + var targetAssembly = EditorCompilationInterface.Instance.GetTargetAssemblyDetails(reference.Groups["dllname"].Value); + ScriptingLanguage targetLanguage = ScriptingLanguage.None; + if (targetAssembly != null) + targetLanguage = (ScriptingLanguage)Enum.Parse(typeof(ScriptingLanguage), targetAssembly.Language.GetLanguageName(), true); + referencedProject = reference.Groups["project"].Value; + projectBuilder.Append(" ").Append(WindowsNewline); + projectBuilder.Append(" {").Append(ProjectGuid(Path.Combine("Temp", reference.Groups["project"].Value + ".dll"))).Append("}").Append(WindowsNewline); + projectBuilder.Append(" ").Append(referencedProject).Append("").Append(WindowsNewline); + projectBuilder.AppendLine(" "); + } + } + + projectBuilder.Append(ProjectFooter(island)); + return projectBuilder.ToString(); + } + + static void AppendReference(string fullReference, StringBuilder projectBuilder) + { + //replace \ with / and \\ with / + var escapedFullPath = SecurityElement.Escape(fullReference); + escapedFullPath = escapedFullPath.Replace("\\", "/"); + escapedFullPath = escapedFullPath.Replace("\\\\", "/"); + projectBuilder.Append(" ").Append(WindowsNewline); + projectBuilder.Append(" ").Append(escapedFullPath).Append("").Append(WindowsNewline); + projectBuilder.Append(" ").Append(WindowsNewline); + } + + public string ProjectFile(MonoIsland island) + { + ScriptingLanguage language = ScriptingLanguageFor(island); + return Path.Combine(_projectDirectory, string.Format("{0}{1}", Utility.FileNameWithoutExtension(island._output), ProjectExtensions[language])); + } + + internal string SolutionFile() + { + return Path.Combine(_projectDirectory, string.Format("{0}.sln", _projectName)); + } + + private string ProjectHeader(MonoIsland island, + IEnumerable responseFilesData) + { + string targetframeworkversion = "v3.5"; + string targetLanguageVersion = "4"; + string toolsversion = "4.0"; + string productversion = "10.0.20506"; + string baseDirectory = "."; + string cscToolPath = "$(CscToolPath)"; + string cscToolExe = "$(CscToolExe)"; + ScriptingLanguage language = ScriptingLanguageFor(island); + + if (PlayerSettingsEditor.IsLatestApiCompatibility(island._api_compatibility_level)) + { + targetframeworkversion = "v4.7.1"; + targetLanguageVersion = "latest"; + + cscToolPath = Paths.Combine(EditorApplication.applicationContentsPath, "Tools", "RoslynScripts"); + if (Application.platform == RuntimePlatform.WindowsEditor) + cscToolExe = "unity_csc.bat"; + else + cscToolExe = "unity_csc.sh"; + + cscToolPath = Paths.UnifyDirectorySeparator(cscToolPath); + } + else if (_settings.VisualStudioVersion == 9) + { + toolsversion = "3.5"; + productversion = "9.0.21022"; + } + + var arguments = new object[] + { + toolsversion, productversion, ProjectGuid(island._output), + _settings.EngineAssemblyPath, + _settings.EditorAssemblyPath, + string.Join(";", new[] { "DEBUG", "TRACE"}.Concat(island._defines).Concat(responseFilesData.SelectMany(x => x.Defines)).Distinct().ToArray()), + MSBuildNamespaceUri, + Utility.FileNameWithoutExtension(island._output), + EditorSettings.projectGenerationRootNamespace, + targetframeworkversion, + targetLanguageVersion, + baseDirectory, + island._allowUnsafeCode | responseFilesData.Any(x => x.Unsafe), + cscToolPath, + cscToolExe, + }; + + try + { + return string.Format(_settings.GetProjectHeaderTemplate(language), arguments); + } + catch (Exception) + { + throw new System.NotSupportedException("Failed creating c# project because the c# project header did not have the correct amount of arguments, which is " + arguments.Length); + } + } + + private void SyncSolution(IEnumerable islands) + { + SyncSolutionFileIfNotChanged(SolutionFile(), SolutionText(islands, ModeForCurrentExternalEditor())); + } + + private static Mode ModeForCurrentExternalEditor() + { + #pragma warning disable 618 + var scriptEditor = ScriptEditorUtility.GetScriptEditorFromPreferences(); + + if (scriptEditor == ScriptEditorUtility.ScriptEditor.VisualStudio || + scriptEditor == ScriptEditorUtility.ScriptEditor.VisualStudioExpress) + return Mode.UnityScriptAsPrecompiledAssembly; + + return EditorPrefs.GetBool("kExternalEditorSupportsUnityProj", false) ? Mode.UnityScriptAsUnityProj : Mode.UnityScriptAsPrecompiledAssembly; + } + + private string SolutionText(IEnumerable islands, Mode mode) + { + var fileversion = "11.00"; + var vsversion = "2010"; + if (_settings.VisualStudioVersion == 9) + { + fileversion = "10.00"; + vsversion = "2008"; + } + var relevantIslands = RelevantIslandsForMode(islands, mode); + string projectEntries = GetProjectEntries(relevantIslands); + string projectConfigurations = string.Join(WindowsNewline, relevantIslands.Select(i => GetProjectActiveConfigurations(ProjectGuid(i._output))).ToArray()); + return string.Format(_settings.SolutionTemplate, fileversion, vsversion, projectEntries, projectConfigurations); + } + + private static IEnumerable RelevantIslandsForMode(IEnumerable islands, Mode mode) + { + IEnumerable relevantIslands = islands.Where(i => (mode == Mode.UnityScriptAsUnityProj || ScriptingLanguage.CSharp == ScriptingLanguageFor(i))); + return relevantIslands; + } + + /// + /// Get a Project("{guid}") = "MyProject", "MyProject.unityproj", "{projectguid}" + /// entry for each relevant language + /// + internal string GetProjectEntries(IEnumerable islands) + { + var projectEntries = islands.Select(i => string.Format( + DefaultSynchronizationSettings.SolutionProjectEntryTemplate, + SolutionGuid(i), Utility.FileNameWithoutExtension(i._output), Path.GetFileName(ProjectFile(i)), ProjectGuid(i._output) + )); + + return string.Join(WindowsNewline, projectEntries.ToArray()); + } + + /// + /// Generate the active configuration string for a given project guid + /// + private string GetProjectActiveConfigurations(string projectGuid) + { + return string.Format( + DefaultSynchronizationSettings.SolutionProjectConfigurationTemplate, + projectGuid); + } + + private string EscapedRelativePathFor(string file) + { + var projectDir = _projectDirectory.ConvertSeparatorsToWindows(); + file = file.ConvertSeparatorsToWindows(); + var path = Paths.SkipPathPrefix(file, projectDir); + if (PackageManager.Folders.IsPackagedAssetPath(path.ConvertSeparatorsToUnity())) + { + // We have to normalize the path, because the PackageManagerRemapper assumes + // dir seperators will be os specific. + var absolutePath = Path.GetFullPath(path.NormalizePath()).ConvertSeparatorsToWindows(); + path = Paths.SkipPathPrefix(absolutePath, projectDir); + } + return SecurityElement.Escape(path); + } + + string ProjectGuid(string assembly) + { + return SolutionGuidGenerator.GuidForProject(_projectName + Utility.FileNameWithoutExtension(assembly)); + } + + string SolutionGuid(MonoIsland island) + { + return SolutionGuidGenerator.GuidForSolution(_projectName, island.GetExtensionOfSourceFiles()); + } + + string ProjectFooter(MonoIsland island) + { + return _settings.GetProjectFooterTemplate(ScriptingLanguageFor(island)); + } + + [Obsolete("Use AssemblyHelper.IsManagedAssembly")] + public static bool IsManagedAssembly(string file) + { + return AssemblyHelper.IsManagedAssembly(file); + } + + public static string GetProjectExtension(ScriptingLanguage language) + { + if (!ProjectExtensions.ContainsKey(language)) + throw new ArgumentException("Unsupported language", "language"); + + return ProjectExtensions[language]; + } + + public void GenerateAll(bool generateAll) + { + m_ShouldGenerateAll = generateAll; + } + } +} diff --git a/Editor/Mono/VisualStudioIntegration/UnityVSSupport.cs b/Editor/Mono/VisualStudioIntegration/UnityVSSupport.cs new file mode 100644 index 0000000000..394ea49a36 --- /dev/null +++ b/Editor/Mono/VisualStudioIntegration/UnityVSSupport.cs @@ -0,0 +1,367 @@ +// 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.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using Microsoft.Win32; +using Unity.CodeEditor; +using UnityEditorInternal; +using UnityEngine; +using RequiredByNativeCodeAttribute = UnityEngine.Scripting.RequiredByNativeCodeAttribute; + +namespace UnityEditor.VisualStudioIntegration +{ + internal class UnityVSSupport + { + private static bool m_ShouldUnityVSBeActive; + public static string s_UnityVSBridgeToLoad; + private static bool? s_IsUnityVSEnabled; + private static string s_AboutLabel; + + [RequiredByNativeCode] + public static void InitializeUnityVSSupport() + { + Initialize(null); + } + + public static void Initialize(string editorPath) + { + var externalEditor = editorPath ?? ScriptEditorUtility.GetExternalScriptEditor(); + + if (Application.platform == RuntimePlatform.OSXEditor) + { + InitializeVSForMac(externalEditor); + return; + } + + if (Application.platform == RuntimePlatform.WindowsEditor) + InitializeVisualStudio(externalEditor); + } + + private static void InitializeVSForMac(string externalEditor) + { + Version vsfmVersion; + if (!IsVSForMac(externalEditor, out vsfmVersion)) + return; + + m_ShouldUnityVSBeActive = true; + + var bridgeFile = GetVSForMacBridgeAssembly(externalEditor, vsfmVersion); + if (string.IsNullOrEmpty(bridgeFile) || !File.Exists(bridgeFile)) + { + Console.WriteLine("Unable to find Tools for Unity bridge dll for Visual Studio for Mac " + externalEditor); + return; + } + + s_UnityVSBridgeToLoad = bridgeFile; + InternalEditorUtility.RegisterPrecompiledAssembly(Path.GetFileNameWithoutExtension(bridgeFile), bridgeFile); + } + + private static bool IsVSForMac(string externalEditor, out Version vsfmVersion) + { + vsfmVersion = null; + + if (!ScriptEditorUtility.IsVisualStudioForMac(externalEditor)) + return false; + + // We need to extract the version used by VS for Mac + // to lookup its addin registry + try + { + return GetVSForMacVersion(externalEditor, out vsfmVersion); + } + catch (Exception e) + { + Console.WriteLine("Failed to read Visual Studio for Mac information: {0}", e); + return false; + } + } + + private static bool GetVSForMacVersion(string externalEditor, out Version vsfmVersion) + { + vsfmVersion = null; + + // Read the full VS for Mac version from the plist, it will look like this: + // + // CFBundleShortVersionString + // X.X.X.X + + var plist = Path.Combine(externalEditor, "Contents/Info.plist"); + if (!File.Exists(plist)) + return false; + + const string versionStringRegex = @"\CFBundleShortVersionString\\s+\(?\d+\.\d+\.\d+\.\d+?)\"; + + var file = File.ReadAllText(plist); + var match = Regex.Match(file, versionStringRegex); + var versionGroup = match.Groups["version"]; + if (!versionGroup.Success) + return false; + + vsfmVersion = new Version(versionGroup.Value); + return true; + } + + private static string GetVSForMacBridgeAssembly(string externalEditor, Version vsfmVersion) + { + // Check first if we're overriden + // Useful when developing UnityVS for Mac + var bridge = Environment.GetEnvironmentVariable("VSTUM_BRIDGE"); + if (!string.IsNullOrEmpty(bridge) && File.Exists(bridge)) + return bridge; + + // Look for installed addin + const string addinBridge = "Editor/SyntaxTree.VisualStudio.Unity.Bridge.dll"; + const string addinName = "MonoDevelop.Unity"; + + // Check if we're installed in the user addins repository + // ~/Library/Application Support/VisualStudio/X.0/LocalInstall/Addins + var localAddins = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.Personal), + "Library/Application Support/VisualStudio/" + vsfmVersion.Major + ".0" + "/LocalInstall/Addins"); + + // In the user addins repository, the addins are suffixed by their versions, like `MonoDevelop.Unity.1.0` + // When installing another local user addin, MD will remove files inside the folder + // So we browse all VSTUM addins, and return the one with a bridge, which is the one MD will load + if (Directory.Exists(localAddins)) + { + foreach (var folder in Directory.GetDirectories(localAddins, addinName + "*", SearchOption.TopDirectoryOnly)) + { + bridge = Path.Combine(folder, addinBridge); + if (File.Exists(bridge)) + return bridge; + } + } + + // Check in Visual Studio.app/ + // In that case the name of the addin is used + bridge = Path.Combine(externalEditor, "Contents/Resources/lib/monodevelop/AddIns/" + addinName + "/" + addinBridge); + if (File.Exists(bridge)) + return bridge; + + return null; + } + + private static void InitializeVisualStudio(string externalEditor) + { + if (externalEditor.EndsWith("UnityVS.OpenFile.exe")) + { + externalEditor = SyncVS.FindBestVisualStudio(); + if (externalEditor != null) + CodeEditor.SetExternalScriptEditor(externalEditor); + } + + VisualStudioVersion vsVersion; + if (!IsVisualStudio(externalEditor, out vsVersion)) + return; + + m_ShouldUnityVSBeActive = true; + + var bridgeFile = GetVstuBridgeAssembly(vsVersion); + if (bridgeFile == null) + { + Console.WriteLine("Unable to find bridge dll in registry for Microsoft Visual Studio Tools for Unity for " + externalEditor); + return; + } + if (!File.Exists(bridgeFile)) + { + Console.WriteLine("Unable to find bridge dll on disk for Microsoft Visual Studio Tools for Unity for " + bridgeFile); + return; + } + s_UnityVSBridgeToLoad = bridgeFile; + InternalEditorUtility.RegisterPrecompiledAssembly(Path.GetFileNameWithoutExtension(bridgeFile), bridgeFile); + } + + static bool IsVisualStudio(string externalEditor, out VisualStudioVersion vsVersion) + { + if (string.IsNullOrEmpty(externalEditor)) + { + vsVersion = VisualStudioVersion.Invalid; + return false; + } + + // If it's a VS found through envvars or the registry + var matches = SyncVS.InstalledVisualStudios.Where(kvp => kvp.Value.Any(v => UnityEditor.Utils.Paths.AreEqual(v.Path, externalEditor, true))).ToArray(); + if (matches.Length > 0) + { + vsVersion = matches[0].Key; + return true; + } + + // If it's a side-by-side VS selected manually + if (externalEditor.EndsWith("devenv.exe", StringComparison.OrdinalIgnoreCase)) + { + if (TryGetVisualStudioVersion(externalEditor, out vsVersion)) + return true; + } + + vsVersion = VisualStudioVersion.Invalid; + return false; + } + + private static bool TryGetVisualStudioVersion(string externalEditor, out VisualStudioVersion vsVersion) + { + switch (ProductVersion(externalEditor).Major) + { + case 9: + vsVersion = VisualStudioVersion.VisualStudio2008; + return true; + case 10: + vsVersion = VisualStudioVersion.VisualStudio2010; + return true; + case 11: + vsVersion = VisualStudioVersion.VisualStudio2012; + return true; + case 12: + vsVersion = VisualStudioVersion.VisualStudio2013; + return true; + case 14: + vsVersion = VisualStudioVersion.VisualStudio2015; + return true; + case 15: + vsVersion = VisualStudioVersion.VisualStudio2017; + return true; + case 16: + vsVersion = VisualStudioVersion.VisualStudio2019; + return true; + } + + vsVersion = VisualStudioVersion.Invalid; + return false; + } + + private static Version ProductVersion(string externalEditor) + { + try + { + return new Version(System.Diagnostics.FileVersionInfo.GetVersionInfo(externalEditor).ProductVersion); + } + catch (Exception) + { + return new Version(0, 0); + } + } + + //Called by UnityVS through reflection + static public bool ShouldUnityVSBeActive() + { + return m_ShouldUnityVSBeActive; + } + + static string GetAssemblyLocation(System.Reflection.Assembly a) + { + try + { + return a.Location; + } + catch (NotSupportedException) + { + return null; + } + } + + [RequiredByNativeCode] + static public bool IsUnityVSEnabled() + { + if (!m_ShouldUnityVSBeActive) + { + return false; + } + if (!s_IsUnityVSEnabled.HasValue) + s_IsUnityVSEnabled = AppDomain.CurrentDomain.GetAssemblies().Any(a => GetAssemblyLocation(a) == s_UnityVSBridgeToLoad); + + return s_IsUnityVSEnabled.Value; + } + + private static string GetVstuBridgeAssembly(VisualStudioVersion version) + { + try + { + var vsVersion = string.Empty; + + switch (version) + { + // Starting with VS 15, the registry key is using the VS version + // to avoid taking a dependency on the product name + case VisualStudioVersion.VisualStudio2017: + vsVersion = "15.0"; + break; + case VisualStudioVersion.VisualStudio2019: + vsVersion = "16.0"; + break; + // VS 2015 and under are still installed in the registry + // using their project names + case VisualStudioVersion.VisualStudio2015: + vsVersion = "2015"; + break; + case VisualStudioVersion.VisualStudio2013: + vsVersion = "2013"; + break; + case VisualStudioVersion.VisualStudio2012: + vsVersion = "2012"; + break; + case VisualStudioVersion.VisualStudio2010: + vsVersion = "2010"; + break; + } + + // search first for the current user with a fallback to machine wide setting + return GetVstuBridgePathFromRegistry(vsVersion, true) + ?? GetVstuBridgePathFromRegistry(vsVersion, false); + } + catch (Exception) + { + return null; + } + } + + private static string GetVstuBridgePathFromRegistry(string vsVersion, bool currentUser) + { + var registryKey = string.Format(@"{0}\Software\Microsoft\Microsoft Visual Studio {1} Tools for Unity", + currentUser ? "HKEY_CURRENT_USER" : "HKEY_LOCAL_MACHINE", + vsVersion); + + return (string)Registry.GetValue(registryKey, "UnityExtensionPath", null); + } + + public static void ScriptEditorChanged(string editorPath) + { + if (Application.platform != RuntimePlatform.OSXEditor && Application.platform != RuntimePlatform.WindowsEditor) + return; + + // We reload the domain because selecting a different editor requires loading a different UnityVS + Initialize(editorPath); + + InternalEditorUtility.RequestScriptReload(); + } + + public static string GetAboutWindowLabel() + { + if (s_AboutLabel != null) + return s_AboutLabel; + + s_AboutLabel = CalculateAboutWindowLabel(); + return s_AboutLabel; + } + + private static string CalculateAboutWindowLabel() + { + if (!IsUnityVSEnabled()) + return ""; + + var assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => GetAssemblyLocation(a) == s_UnityVSBridgeToLoad); + if (assembly == null) + return ""; + + var sb = new StringBuilder("Microsoft Visual Studio Tools for Unity "); + sb.Append(assembly.GetName().Version); + sb.Append(" enabled"); + + return sb.ToString(); + } + } +} diff --git a/Editor/Mono/WebViewEditorWindow/WebViewEditorWindow.cs b/Editor/Mono/WebViewEditorWindow/WebViewEditorWindow.cs index ad0d975dbd..0e3a4c9fcc 100644 --- a/Editor/Mono/WebViewEditorWindow/WebViewEditorWindow.cs +++ b/Editor/Mono/WebViewEditorWindow/WebViewEditorWindow.cs @@ -2,13 +2,8 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License -using System.Collections.Generic; using UnityEngine; -using System.Text; using System.IO; -using System; -using UnityEditor; -using UnityEditorInternal; namespace UnityEditor.Web { @@ -379,42 +374,6 @@ private void CreateScriptObject() scriptObject.webView = webView; } - private void InvokeJSMethod(string objectName, string name, params object[] args) - { - if (!webView) - return; - - var scriptCodeBuffer = new StringBuilder(); - scriptCodeBuffer.Append(objectName); - scriptCodeBuffer.Append('.'); - scriptCodeBuffer.Append(name); - scriptCodeBuffer.Append('('); - - var isFirst = true; - foreach (var arg in args) - { - if (!isFirst) - scriptCodeBuffer.Append(','); - - // Quote strings. This is pretty simple-minded as we don't escape - // things within the string. - var isString = arg is string; - if (isString) - scriptCodeBuffer.Append('"'); - - scriptCodeBuffer.Append(arg); - - if (isString) - scriptCodeBuffer.Append('"'); - - isFirst = false; - } - - scriptCodeBuffer.Append(");"); - - webView.ExecuteJavascript(scriptCodeBuffer.ToString()); - } - private void SetFocus(bool value) { // Giving the focus to the browser's native window will cause our GuiView's diff --git a/External/Unity.Compiler.Client/Unity.CompilationPipeline.Common.dll b/External/Unity.Compiler.Client/Unity.CompilationPipeline.Common.dll new file mode 100644 index 0000000000..b90e62f25e Binary files /dev/null and b/External/Unity.Compiler.Client/Unity.CompilationPipeline.Common.dll differ diff --git a/External/il2cpp/il2cpp/UnityLinker/Linker/EditorIntegration/SharedWithEditor.cs b/External/il2cpp/il2cpp/UnityLinker/Linker/EditorIntegration/SharedWithEditor.cs index fa76729ac9..e0c0645af0 100644 --- a/External/il2cpp/il2cpp/UnityLinker/Linker/EditorIntegration/SharedWithEditor.cs +++ b/External/il2cpp/il2cpp/UnityLinker/Linker/EditorIntegration/SharedWithEditor.cs @@ -67,6 +67,7 @@ public override string ToString() } } + [DebuggerDisplay("{module}:{name}")] [System.Serializable] public class NativeTypeData { @@ -74,6 +75,11 @@ public class NativeTypeData public string name; [UnityEngine.SerializeField] public string module; + + [UnityEngine.SerializeField] + public string baseName; + [UnityEngine.SerializeField] + public string baseModule; } } diff --git a/Modules/AndroidJNI/AndroidJava.cs b/Modules/AndroidJNI/AndroidJava.cs index eb181574ff..8690e5c33c 100644 --- a/Modules/AndroidJNI/AndroidJava.cs +++ b/Modules/AndroidJNI/AndroidJava.cs @@ -1061,6 +1061,7 @@ public static object UnboxArray(AndroidJavaObject obj) for (int i = 0; i < arrayLength; ++i) array.SetValue(Unbox(arrayUtil.CallStatic("get", obj, i)), i); + arrayUtil.Dispose(); return array; } @@ -1451,8 +1452,10 @@ public static string GetSignature(object obj) } else if (obj is AndroidJavaProxy) { - AndroidJavaObject javaClass = new AndroidJavaObject(((AndroidJavaProxy)obj).javaInterface.GetRawClass()); - return "L" + javaClass.Call("getName") + ";"; + using (var javaClass = new AndroidJavaObject(((AndroidJavaProxy)obj).javaInterface.GetRawClass())) + { + return "L" + javaClass.Call("getName") + ";"; + } } else if (type.Equals(typeof(AndroidJavaRunnable))) { @@ -1464,7 +1467,7 @@ public static string GetSignature(object obj) } else if (type.Equals(typeof(AndroidJavaObject))) { - if (obj == type) + if (obj == (object)type) { return "Ljava/lang/Object;"; } @@ -1487,7 +1490,7 @@ public static string GetSignature(object obj) } else { - throw new Exception("JNI: Unknown signature for type '" + type + "' (obj = " + obj + ") " + (type == obj ? "equal" : "instance")); + throw new Exception("JNI: Unknown signature for type '" + type + "' (obj = " + obj + ") " + ((object)type == obj ? "equal" : "instance")); } return ""; } diff --git a/Modules/Animation/ScriptBindings/AnimationPlayableOutputExtensions.bindings.cs b/Modules/Animation/ScriptBindings/AnimationPlayableOutputExtensions.bindings.cs index 004ccc8348..f3439bd196 100644 --- a/Modules/Animation/ScriptBindings/AnimationPlayableOutputExtensions.bindings.cs +++ b/Modules/Animation/ScriptBindings/AnimationPlayableOutputExtensions.bindings.cs @@ -32,9 +32,24 @@ public static void SetAnimationStreamSource(this AnimationPlayableOutput output, InternalSetAnimationStreamSource(output.GetHandle(), streamSource); } + public static ushort GetSortingOrder(this AnimationPlayableOutput output) + { + return (ushort)InternalGetSortingOrder(output.GetHandle()); + } + + public static void SetSortingOrder(this AnimationPlayableOutput output, ushort sortingOrder) + { + InternalSetSortingOrder(output.GetHandle(), (int)sortingOrder); + } + [NativeThrows] extern private static AnimationStreamSource InternalGetAnimationStreamSource(PlayableOutputHandle output); [NativeThrows] extern private static void InternalSetAnimationStreamSource(PlayableOutputHandle output, AnimationStreamSource streamSource); + + [NativeThrows] + extern private static int InternalGetSortingOrder(PlayableOutputHandle output); + [NativeThrows] + extern private static void InternalSetSortingOrder(PlayableOutputHandle output, int sortingOrder); }; } diff --git a/Modules/Animation/ScriptBindings/AnimatorJobExtensions.bindings.cs b/Modules/Animation/ScriptBindings/AnimatorJobExtensions.bindings.cs index 2529262c96..966977c528 100644 --- a/Modules/Animation/ScriptBindings/AnimatorJobExtensions.bindings.cs +++ b/Modules/Animation/ScriptBindings/AnimatorJobExtensions.bindings.cs @@ -7,6 +7,8 @@ using UnityEngine.Internal; using UnityEngine.Scripting.APIUpdating; +using Unity.Jobs; + namespace UnityEngine.Animations { [MovedFrom("UnityEngine.Experimental.Animations")] @@ -26,6 +28,11 @@ public enum CustomStreamPropertyType [StaticAccessor("AnimatorJobExtensionsBindings", StaticAccessorType.DoubleColon)] public static class AnimatorJobExtensions { + public static void AddJobDependency(this Animator animator, JobHandle jobHandle) + { + InternalAddJobDependency(animator, jobHandle); + } + public static TransformStreamHandle BindStreamTransform(this Animator animator, Transform transform) { TransformStreamHandle transformStreamHandle = new TransformStreamHandle(); @@ -96,6 +103,8 @@ internal static void UnbindAllHandles(this Animator animator) InternalUnbindAllHandles(animator); } + extern private static void InternalAddJobDependency([NotNull] Animator animator, JobHandle jobHandle); + extern private static void InternalBindStreamTransform([NotNull] Animator animator, [NotNull] Transform transform, out TransformStreamHandle transformStreamHandle); extern private static void InternalBindStreamProperty([NotNull] Animator animator, [NotNull] Transform transform, [NotNull] Type type, [NotNull] string property, bool isObjectReference, out PropertyStreamHandle propertyStreamHandle); diff --git a/Modules/AssetDatabase/Editor/ScriptBindings/AssetDatabaseExperimental.bindings.cs b/Modules/AssetDatabase/Editor/ScriptBindings/AssetDatabaseExperimental.bindings.cs index 21dfce4012..40791ea965 100644 --- a/Modules/AssetDatabase/Editor/ScriptBindings/AssetDatabaseExperimental.bindings.cs +++ b/Modules/AssetDatabase/Editor/ScriptBindings/AssetDatabaseExperimental.bindings.cs @@ -24,24 +24,20 @@ public struct Counter public struct CacheServerCounters { - public Counter resolveRequests; - public Counter resolveReplies; + public Counter metadataRequested; + public Counter metadataDownloaded; + public Counter metadataFailedToDownload; + public Counter metadataUploaded; + public Counter metadataFailedToUpload; + public Counter metadataVersionsDownloaded; + public Counter metadataMatched; - public Counter artifactsRequestedResolved; - public Counter artifactsInResolveReplies; - public Counter artifactVersionsInResolveReplies; - public Counter artifactsMatchedResolveVersion; - - public Counter artifactFilesDownloaded; public Counter artifactsDownloaded; - - public Counter artifactFilesUploaded; + public Counter artifactFilesDownloaded; + public Counter artifactFilesFailedToDownload; public Counter artifactsUploaded; - - public Counter reliabilityChecks; - public Counter reliabilityCheckReportedIndeterminism; - public Counter reliabilityCheckReportedNewArtifactVersion; - public Counter reliabilityCheckReportedArtifactVersionMatched; + public Counter artifactFilesUploaded; + public Counter artifactFilesFailedToUpload; public Counter connects; public Counter disconnects; diff --git a/Modules/AssetDatabase/Editor/V2/MultiArtifactTestImporter.bindings.cs b/Modules/AssetDatabase/Editor/V2/MultiArtifactTestImporter.bindings.cs index 4f72fba386..eca8526823 100644 --- a/Modules/AssetDatabase/Editor/V2/MultiArtifactTestImporter.bindings.cs +++ b/Modules/AssetDatabase/Editor/V2/MultiArtifactTestImporter.bindings.cs @@ -9,6 +9,7 @@ namespace UnityEditor.Experimental { // AssetImporter for importing ReferenceArtifactGenerator [NativeHeader("Modules/AssetDatabase/Editor/V2/MultiArtifactTestImporter.h")] + [ExcludeFromPreset] internal partial class MultiArtifactTestImporter : AssetImporter { } diff --git a/Modules/AssetPipelineEditor/AssetPostprocessors/ModelImporterPostProcessor.cs b/Modules/AssetPipelineEditor/AssetPostprocessors/ModelImporterPostProcessor.cs index dc2fa87aca..9f65f30847 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,6 +13,8 @@ namespace UnityEditor { internal class ModelImporterPostProcessor : AssetPostprocessor { + static bool AskedForBumpMap = false; + static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromPath) { if (AssetDatabase.IsOnDemandModeEnabled()) @@ -22,6 +25,7 @@ static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAsse } List loadedAssets = new List(); + bool oneFound = false; try { foreach (var assetPath in importedAssets) @@ -39,6 +43,7 @@ static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAsse var embeddedMaterials = AssetDatabase.LoadAllAssetsAtPath(assetPath).OfType(); foreach (var material in embeddedMaterials) { + oneFound = true; BumpMapSettings.PerformBumpMapCheck(material); } } @@ -46,11 +51,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/ModelImporterRigEditor.cs b/Modules/AssetPipelineEditor/ImportSettings/ModelImporterRigEditor.cs index bac0a041dc..e19b56dc76 100644 --- a/Modules/AssetPipelineEditor/ImportSettings/ModelImporterRigEditor.cs +++ b/Modules/AssetPipelineEditor/ImportSettings/ModelImporterRigEditor.cs @@ -5,20 +5,14 @@ using System; using UnityEngine; using UnityEditor.SceneManagement; -using UnityEditorInternal; using System.Collections.Generic; using Object = UnityEngine.Object; -using System.IO; -using System.Linq; using UnityEditor.Experimental.AssetImporters; -using UnityEditor.IMGUI.Controls; namespace UnityEditor { internal class ModelImporterRigEditor : BaseAssetImporterTabUI { - const float kDeleteWidth = 17; - ModelImporter singleImporter { get { return targets[0] as ModelImporter; } } public int m_SelectedClipIndex = -1; diff --git a/Modules/AssetPipelineEditor/ImportSettings/VideoClipImporterInspector.cs b/Modules/AssetPipelineEditor/ImportSettings/VideoClipImporterInspector.cs index bf70ad8735..59e56e2ccd 100644 --- a/Modules/AssetPipelineEditor/ImportSettings/VideoClipImporterInspector.cs +++ b/Modules/AssetPipelineEditor/ImportSettings/VideoClipImporterInspector.cs @@ -159,10 +159,12 @@ class Styles EditorGUIUtility.IconContent("preAudioPlayOff"), EditorGUIUtility.IconContent("preAudioPlayOn") }; + public GUIContent globalTranscodeOptionsContent = EditorGUIUtility.TextContent( + "Global Transcode Options"); public GUIContent keepAlphaContent = EditorGUIUtility.TextContent( - "Keep Alpha|If the source clip has alpha, this will encode it in the resulting clip so that transparency is usable during render."); + "Keep Alpha|If the source clip has alpha, it will be preserved during transcoding so that transparency is usable during render."); public GUIContent deinterlaceContent = EditorGUIUtility.TextContent( - "Deinterlace|Remove interlacing on this video."); + "Deinterlace|Remove interlacing on this video during transcoding."); public GUIContent flipHorizontalContent = EditorGUIUtility.TextContent( "Flip Horizontally|Flip the video horizontally during transcoding."); public GUIContent flipVerticalContent = EditorGUIUtility.TextContent( @@ -187,6 +189,8 @@ class Styles "Spatial Quality|Adds a downsize during import to reduce bitrate using resolution."); public GUIContent transcodeWarning = EditorGUIUtility.TextContent( "Not all platforms transcoded. Clip is not guaranteed to be compatible on platforms without transcoding."); + public GUIContent transcodeOptionsWarning = EditorGUIUtility.TextContent( + "Global transcode options are not applied on all platforms. You must enable \"Transcode\" for these to take effect."); public GUIContent transcodeSkippedWarning = EditorGUIUtility.TextContent( "Transcode was skipped. Current clip does not match import settings. Reimport to resolve."); public GUIContent multipleTranscodeSkippedWarning = EditorGUIUtility.TextContent( @@ -197,13 +201,6 @@ class Styles static Styles s_Styles; - const int kNarrowLabelWidth = 42; - const int kToggleButtonWidth = 16; - const int kMinCustomWidth = 1; - const int kMaxCustomWidth = 16384; - const int kMinCustomHeight = 1; - const int kMaxCustomHeight = 16384; - // Don't show the imported movie as a separate editor public override bool showImportedObject { get { return false; } } @@ -308,6 +305,37 @@ private bool AnySettingsNotTranscoded() return false; } + private bool AnyUnappliedGlobalTranscodeOptions() + { + // Scan through all selected clips (eg. multi-select) + for (var i = 0; i < targets.Length; i++) + { + // Check "global" (eg. non-platform specific options) for any that actually apply + // non trivial processing during transcode. + var importer = targets[i] as VideoClipImporter; + if (importer != null && + (importer.flipHorizontal || + importer.flipVertical || + importer.deinterlaceMode != VideoDeinterlaceMode.Off || + (!importer.importAudio && importer.sourceAudioTrackCount > 0) || + (!importer.keepAlpha && importer.sourceHasAlpha))) + { + // Check all platform-specific options to see if any platform has transcoding + // disabled. + var settings = extraDataTargets[i] as TargetSettings; + if (settings != null) + { + foreach (var setting in settings.allSettings) + { + if (setting.overridePlatform && !setting.settings.enableTranscoding) + return true; + } + } + } + } + return false; + } + private void OnCrossTargetInspectorGUI() { bool sourcesHaveAlpha = true; @@ -325,10 +353,16 @@ private void OnCrossTargetInspectorGUI() if (EditorGUI.EndChangeCheck()) m_ColorSpace.enumValueIndex = (int)(sRGB ? VideoColorSpace.sRGB : VideoColorSpace.Linear); + EditorGUILayout.Space(); + + EditorGUILayout.LabelField(s_Styles.globalTranscodeOptionsContent, EditorStyles.boldLabel); + EditorGUI.indentLevel++; + if (sourcesHaveAlpha) + { EditorGUILayout.PropertyField(m_EncodeAlpha, s_Styles.keepAlphaContent); - - EditorGUILayout.Space(); + EditorGUILayout.Space(); + } EditorGUILayout.PropertyField(m_Deinterlace, s_Styles.deinterlaceContent); EditorGUILayout.Space(); @@ -341,6 +375,8 @@ private void OnCrossTargetInspectorGUI() { EditorGUILayout.PropertyField(m_ImportAudio, s_Styles.importAudioContent); } + + EditorGUI.indentLevel--; } private void FrameSettingsGUI(SerializedProperty videoImporterTargetSettings) @@ -528,6 +564,10 @@ public override void OnInspectorGUI() if (AnySettingsNotTranscoded()) EditorGUILayout.HelpBox(s_Styles.transcodeWarning.text, MessageType.Info); + // Warn the user if any of the global transcode settings are on, but transcoding isn't applied + if (AnyUnappliedGlobalTranscodeOptions()) + EditorGUILayout.HelpBox(s_Styles.transcodeOptionsWarning.text, MessageType.Warning); + foreach (var t in targets) { VideoClipImporter importer = t as VideoClipImporter; diff --git a/Modules/AssetPipelineEditor/Public/ModelImporting/ModelImporter.bindings.cs b/Modules/AssetPipelineEditor/Public/ModelImporting/ModelImporter.bindings.cs index dc0c6b6fff..24159f47ac 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; } } @@ -472,6 +474,11 @@ public extern bool useFileUnits set; } + public extern float fileScale + { + get; + } + public extern bool useFileScale { get; diff --git a/Modules/AssetPipelineEditor/Public/ScriptedImporter.cs b/Modules/AssetPipelineEditor/Public/ScriptedImporter.cs index d35ee57d65..99f43a338f 100644 --- a/Modules/AssetPipelineEditor/Public/ScriptedImporter.cs +++ b/Modules/AssetPipelineEditor/Public/ScriptedImporter.cs @@ -61,7 +61,8 @@ internal static void RegisterScriptedImporters() // Remove intersection? foreach (var x1 in handledExts2) { - if (handledExts.ContainsKey(x1.Key)) + // reject the scripted importers that handle the same extension *AND* are both AutoSelected + if (handledExts.ContainsKey(x1.Key) && attribute.AutoSelect == true && attribute2.AutoSelect == true) { // Log error message and remove from handledExts Debug.LogError(String.Format("Scripted importers {0} and {1} are targeting the {2} extension, rejecting both.", importerType.FullName, (imp as Type).FullName, x1.Key)); @@ -75,7 +76,7 @@ internal static void RegisterScriptedImporters() // Register the importer foreach (var ext in handledExts) - AssetImporter.RegisterImporter(importerType, attribute.version, attribute.importQueuePriority, ext.Key, supportsImportDependencyHinting); + AssetImporter.RegisterImporter(importerType, attribute.version, attribute.importQueuePriority, ext.Key, supportsImportDependencyHinting, attribute.AutoSelect); } } @@ -110,6 +111,8 @@ public class ScriptedImporterAttribute : Attribute public string[] fileExtensions { get; private set; } + public bool AutoSelect = true; + public ScriptedImporterAttribute(int version, string[] exts) { Init(version, exts, 0); diff --git a/Modules/AssetPipelineEditor/Public/TextScriptImporter.bindings.cs b/Modules/AssetPipelineEditor/Public/TextScriptImporter.bindings.cs new file mode 100644 index 0000000000..6b100e5e21 --- /dev/null +++ b/Modules/AssetPipelineEditor/Public/TextScriptImporter.bindings.cs @@ -0,0 +1,13 @@ +// 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 UnityEditor +{ + [NativeHeader("Modules/AssetPipelineEditor/Public/TextScriptImporter.h")] + internal class TextScriptImporter : AssetImporter + { + } +} diff --git a/Modules/Audio/Public/ScriptBindings/AudioMixer.bindings.cs b/Modules/Audio/Public/ScriptBindings/AudioMixer.bindings.cs new file mode 100644 index 0000000000..be06f2a634 --- /dev/null +++ b/Modules/Audio/Public/ScriptBindings/AudioMixer.bindings.cs @@ -0,0 +1,69 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using UnityEngine; +using System; +using JetBrains.Annotations; +using UnityEngine.Bindings; + +namespace UnityEngine.Audio +{ + public enum AudioMixerUpdateMode + { + Normal = 0, + UnscaledTime = 1 + } + + /// A container for DSP graph (audio mix tree) information. + /// An AudioMixer defines the routing graph for audio signals from [[AudioSources]] through to the listener [[AudioListener]] + /// AudioMixers are referenced by AudioListeners and are used to apply effects, attenuation, submixing etc to the audio signal path. + /// + /// SA: [[class-AudioListener|AudioListener component]] in the Components Reference + [ExcludeFromPreset] + [ExcludeFromObjectFactory] + [NativeHeader("Modules/Audio/Public/AudioMixer.h")] + [NativeHeader("Modules/Audio/Public/ScriptBindings/AudioMixer.bindings.h")] + public partial class AudioMixer : Object + { + internal AudioMixer() {} + + [NativeProperty] + public extern AudioMixerGroup outputAudioMixerGroup { get; set; } + + [NativeMethod("FindSnapshotFromName")] + public extern AudioMixerSnapshot FindSnapshot(string name); + + [NativeMethod("AudioMixerBindings::FindMatchingGroups", IsFreeFunction = true, HasExplicitThis = true)] + public extern AudioMixerGroup[] FindMatchingGroups(string subPath); + + internal void TransitionToSnapshot(AudioMixerSnapshot snapshot, float timeToReach) + { + if (snapshot == null) + throw new ArgumentException("null Snapshot passed to AudioMixer.TransitionToSnapshot of AudioMixer '" + name + "'"); + + if (snapshot.audioMixer != this) + throw new ArgumentException("Snapshot '" + snapshot.name + "' passed to AudioMixer.TransitionToSnapshot is not a snapshot from AudioMixer '" + name + "'"); + + TransitionToSnapshotInternal(snapshot, timeToReach); + } + + [NativeMethod("TransitionToSnapshot")] + private extern void TransitionToSnapshotInternal(AudioMixerSnapshot snapshot, float timeToReach); + + [NativeMethod("AudioMixerBindings::TransitionToSnapshots", IsFreeFunction = true, HasExplicitThis = true, ThrowsException = true)] + public extern void TransitionToSnapshots(AudioMixerSnapshot[] snapshots, float[] weights, float timeToReach); + + [NativeProperty] + public extern AudioMixerUpdateMode updateMode { get; set; } + + [NativeMethod] + public extern bool SetFloat(string name, float value); + + [NativeMethod] + public extern bool ClearFloat(string name); + + [NativeMethod] + public extern bool GetFloat(string name, out float value); + } +} diff --git a/Modules/Audio/Public/ScriptBindings/AudioMixerGroup.bindings.cs b/Modules/Audio/Public/ScriptBindings/AudioMixerGroup.bindings.cs new file mode 100644 index 0000000000..1ba37e8199 --- /dev/null +++ b/Modules/Audio/Public/ScriptBindings/AudioMixerGroup.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; +using UnityEngine.Bindings; +using UnityEngine.Internal; + +namespace UnityEngine.Audio +{ + [NativeHeader("Modules/Audio/Public/AudioMixerGroup.h")] + public class AudioMixerGroup : Object, ISubAssetNotDuplicatable + { + // Make constructor internal + internal AudioMixerGroup() {} + + [NativeProperty] + public extern AudioMixer audioMixer { get; } + } +} diff --git a/Modules/Audio/Public/ScriptBindings/AudioMixerSnapshot.bindings.cs b/Modules/Audio/Public/ScriptBindings/AudioMixerSnapshot.bindings.cs new file mode 100644 index 0000000000..29dd7b6915 --- /dev/null +++ b/Modules/Audio/Public/ScriptBindings/AudioMixerSnapshot.bindings.cs @@ -0,0 +1,24 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using UnityEngine; +using UnityEngine.Bindings; +using UnityEngine.Internal; + +namespace UnityEngine.Audio +{ + [NativeHeader("Modules/Audio/Public/AudioMixerSnapshot.h")] + public partial class AudioMixerSnapshot : Object, ISubAssetNotDuplicatable + { + internal AudioMixerSnapshot() {} + + [NativeProperty] + public extern AudioMixer audioMixer { get; } + + public void TransitionTo(float timeToReach) + { + audioMixer.TransitionToSnapshot(this, timeToReach); + } + } +} diff --git a/Modules/AudioEditor/ScriptBindings/AudioMixerController.bindings.cs b/Modules/AudioEditor/ScriptBindings/AudioMixerController.bindings.cs new file mode 100644 index 0000000000..11c78f276b --- /dev/null +++ b/Modules/AudioEditor/ScriptBindings/AudioMixerController.bindings.cs @@ -0,0 +1,136 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using UnityEngine.Audio; +using System.Collections.Generic; +using UnityEngine.Bindings; +using UnityEngine.Scripting; +using UnityEngine; + +namespace UnityEditor.Audio +{ + [RequiredByNativeCode] + internal struct ExposedAudioParameter + { + public GUID guid; + public string name; + } + + [RequiredByNativeCode] + internal struct MixerGroupView + { + public GUID[] guids; + public string name; + } + + ///*undocumented* + [NativeHeader("Editor/Src/Audio/Mixer/AudioMixerController.h")] + [NativeHeader("Modules/AudioEditor/ScriptBindings/AudioMixerController.bindings.h")] + internal partial class AudioMixerController : AudioMixer + { + public AudioMixerController() + { + Internal_CreateAudioMixerController(this); + } + + [FreeFunction("AudioMixerControllerBindings::Internal_CreateAudioMixerController")] + private static extern void Internal_CreateAudioMixerController([Writable] AudioMixerController mono); + + private static void GetGroupsRecurse(AudioMixerGroupController group, List groups) + { + groups.Add(group); + + AudioMixerGroupController[] children = group.children; + for (int i = 0; i < children.Length; i++) + GetGroupsRecurse(children[i], groups); + } + + public AudioMixerGroupController[] allGroups + { + get + { + List groups = new List(); + GetGroupsRecurse(masterGroup, groups); + return groups.ToArray(); + } + } + + public extern int numExposedParameters { [NativeMethod("AudioMixerControllerBindings::GetNumExposedParameters", HasExplicitThis = true, IsFreeFunction = true)] get; } + + public extern ExposedAudioParameter[] exposedParameters { get; set; } + + public extern AudioMixerGroupController masterGroup + { + [NativeName("GetMasterGroupController")] + get; + [NativeName("SetMasterGroupController")] + set; + } + + public extern AudioMixerSnapshot startSnapshot { get; set; } + + public AudioMixerSnapshotController TargetSnapshot { get { return (AudioMixerSnapshotController)currentSnapshot; } set { currentSnapshot = value; } } + + private extern AudioMixerSnapshot currentSnapshot { get; set; } + + public AudioMixerSnapshotController[] snapshots + { + get + { + return System.Array.ConvertAll(snapshots_Internal, ams => (AudioMixerSnapshotController)ams); + } + set + { + snapshots_Internal = System.Array.ConvertAll(value, amsc => (AudioMixerSnapshot)amsc); + ValidateSnapshots(); + } + } + + [NativeName("Snapshots")] + private extern AudioMixerSnapshot[] snapshots_Internal { get; set; } + + private extern void ValidateSnapshots(); + + [NativeMethod("AudioMixerControllerBindings::GetGroupVUInfo", HasExplicitThis = true, IsFreeFunction = true)] + public extern int GetGroupVUInfo(GUID group, bool fader, float[] vuLevel, float[] vuPeak); + + public extern void UpdateMuteSolo(); + + public extern void UpdateBypass(); + + [System.NonSerialized] public int m_HighlightEffectIndex = -1; + + [System.NonSerialized] private List m_CachedSelection = null; + public List CachedSelection + { + get + { + if (m_CachedSelection == null) + m_CachedSelection = new List(); + return m_CachedSelection; + } + } + + public extern int currentViewIndex { get; set; } + + public extern bool CurrentViewContainsGroup(GUID group); + + [NativeName("AudioMixerGroupViews")] + public extern MixerGroupView[] views { get; set; } + + [FreeFunction("AudioMixer::CheckForCyclicReferences")] + static internal extern bool CheckForCyclicReferences(AudioMixer mixer, AudioMixerGroup group); + + [FreeFunction("AudioMixerControllerBindings::GetMaxVolume")] + static internal extern float GetMaxVolume(); + + [FreeFunction("AudioMixerControllerBindings::GetVolumeSplitPoint")] + static internal extern float GetVolumeSplitPoint(); + + public extern bool isSuspended { [NativeMethod("IsSuspended")] get; } + + [FreeFunction("AudioMixerController::EditingTargetSnapshot")] + public extern static bool EditingTargetSnapshot(); + } +} diff --git a/Modules/AudioEditor/ScriptBindings/AudioMixerDescription.bindings.cs b/Modules/AudioEditor/ScriptBindings/AudioMixerDescription.bindings.cs new file mode 100644 index 0000000000..9e72f59b9b --- /dev/null +++ b/Modules/AudioEditor/ScriptBindings/AudioMixerDescription.bindings.cs @@ -0,0 +1,36 @@ +// 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 UnityEditor.Audio +{ + internal struct MixerParameterDefinition + { + public string name; + public string description; + public string units; + public float displayScale; + public float displayExponent; + public float minRange; + public float maxRange; + public float defaultValue; + } + + [StaticAccessor("AudioMixerDescriptionBindings", StaticAccessorType.DoubleColon)] + [NativeHeader("Modules/AudioEditor/ScriptBindings/AudioMixerDescription.bindings.h")] + internal partial class MixerEffectDefinitions + { + private extern static void ClearDefinitionsRuntime(); + + extern private static void AddDefinitionRuntime(string name, MixerParameterDefinition[] parameters); + + extern public static string[] GetAudioEffectNames(); + + extern public static MixerParameterDefinition[] GetAudioEffectParameterDesc(string effectName); + + //Change to use effect + public extern static bool EffectCanBeSidechainTarget(AudioMixerEffectController effect); + } +} diff --git a/Modules/AudioEditor/ScriptBindings/AudioMixerEffectController.bindings.cs b/Modules/AudioEditor/ScriptBindings/AudioMixerEffectController.bindings.cs new file mode 100644 index 0000000000..94d9be4f8c --- /dev/null +++ b/Modules/AudioEditor/ScriptBindings/AudioMixerEffectController.bindings.cs @@ -0,0 +1,97 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using Object = UnityEngine.Object; +using System.Collections.Generic; +using UnityEngine.Scripting; +using UnityEngine.Bindings; +using UnityEngine; + +namespace UnityEditor.Audio +{ + [RequiredByNativeCode] + internal struct MixerEffectParameter + { + public string parameterName; + public GUID GUID; + } + + [NativeHeader("Editor/Src/Audio/Mixer/AudioMixerEffectController.h")] + [NativeHeader("Modules/AudioEditor/ScriptBindings/AudioMixerEffectController.bindings.h")] + internal class AudioMixerEffectController : Object + { + int m_LastCachedGroupDisplayNameID; + string m_DisplayName; + + public AudioMixerEffectController(string name) + { + Internal_CreateAudioMixerEffectController(this, name); + } + + [FreeFunction("AudioMixerEffectControllerBindings::Internal_CreateAudioMixerEffectController")] + private extern static void Internal_CreateAudioMixerEffectController([Writable] AudioMixerEffectController mono, string name); + + public extern GUID effectID { get; } + + public extern string effectName { get; } + + public bool IsSend() { return effectName == "Send"; } + public bool IsReceive() { return effectName == "Receive"; } + public bool IsDuckVolume() { return effectName == "Duck Volume"; } + public bool IsAttenuation() { return effectName == "Attenuation"; } + public bool DisallowsBypass() { return IsSend() || IsReceive() || IsDuckVolume() || IsAttenuation(); } + + public void ClearCachedDisplayName() {m_DisplayName = null; } + + public string GetDisplayString(Dictionary effectMap) + { + AudioMixerGroupController group = effectMap[this]; + if (group.GetInstanceID() != m_LastCachedGroupDisplayNameID || m_DisplayName == null) + { + // Cache display name to prevent string allocs every event + m_DisplayName = group.GetDisplayString() + AudioMixerController.s_GroupEffectDisplaySeperator + AudioMixerController.FixNameForPopupMenu(effectName); + m_LastCachedGroupDisplayNameID = group.GetInstanceID(); + } + return m_DisplayName; + } + + public string GetSendTargetDisplayString(Dictionary effectMap) { return (sendTarget != null) ? sendTarget.GetDisplayString(effectMap) : string.Empty; } + + public extern AudioMixerEffectController sendTarget { get; set; } + + public extern bool enableWetMix { get; set; } + public extern bool bypass { get; set; } + + public extern void PreallocateGUIDs(); + + public extern GUID GetGUIDForMixLevel(); + + public extern float GetValueForMixLevel(AudioMixerController controller, AudioMixerSnapshotController snapshot); + + public extern void SetValueForMixLevel(AudioMixerController controller, AudioMixerSnapshotController snapshot, float value); + + public extern GUID GetGUIDForParameter(string parameterName); + + public extern float GetValueForParameter(AudioMixerController controller, AudioMixerSnapshotController snapshot, string parameterName); + + public extern void SetValueForParameter(AudioMixerController controller, AudioMixerSnapshotController snapshot, string parameterName, float value); + + public bool GetFloatBuffer(AudioMixerController controller, string name, out float[] data, int numsamples) + { + data = new float[numsamples]; + unsafe + { + fixed(float* dataPtr = &data[0]) + return GetFloatBuffer_Internal(controller, name, dataPtr, numsamples); + } + } + + [NativeName("GetFloatBuffer")] + private unsafe extern bool GetFloatBuffer_Internal(AudioMixerController controller, string name, float* buffer, int bufferLength); + + public extern float GetCPUUsage(AudioMixerController controller); + + public extern bool ContainsParameterGUID(GUID guid); + } +} diff --git a/Modules/AudioEditor/ScriptBindings/AudioMixerGroupController.bindings.cs b/Modules/AudioEditor/ScriptBindings/AudioMixerGroupController.bindings.cs new file mode 100644 index 0000000000..9752029985 --- /dev/null +++ b/Modules/AudioEditor/ScriptBindings/AudioMixerGroupController.bindings.cs @@ -0,0 +1,73 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using UnityEngine; +using UnityEngine.Audio; +using UnityEngine.Bindings; + +namespace UnityEditor.Audio +{ + ///*undocumented* + [NativeHeader("Editor/Src/Audio/Mixer/AudioMixerGroupController.h")] + [NativeHeader("Modules/AudioEditor/ScriptBindings/AudioMixerGroupController.bindings.h")] + internal partial class AudioMixerGroupController : AudioMixerGroup + { + public AudioMixerGroupController(AudioMixer owner) + { + Internal_CreateAudioMixerGroupController(this, owner); + } + + [FreeFunction("AudioMixerGroupControllerBindings::Internal_CreateAudioMixerGroupController")] + private extern static void Internal_CreateAudioMixerGroupController([Writable] AudioMixerGroupController mono, AudioMixer owner); + + public extern GUID groupID { get; } + + public extern int userColorIndex { get; set; } + + public extern AudioMixerController controller { get; } + + public extern void PreallocateGUIDs(); + + public extern GUID GetGUIDForVolume(); + + public extern float GetValueForVolume(AudioMixerController controller, AudioMixerSnapshotController snapshot); + + public extern void SetValueForVolume(AudioMixerController controller, AudioMixerSnapshotController snapshot, float value); + + public extern GUID GetGUIDForPitch(); + + public extern float GetValueForPitch(AudioMixerController controller, AudioMixerSnapshotController snapshot); + + public extern void SetValueForPitch(AudioMixerController controller, AudioMixerSnapshotController snapshot, float value); + + public extern GUID GetGUIDForSend(); + + public extern float GetValueForSend(AudioMixerController controller, AudioMixerSnapshotController snapshot); + + public extern void SetValueForSend(AudioMixerController controller, AudioMixerSnapshotController snapshot, float value); + + public extern bool HasDependentMixers(); + + public AudioMixerGroupController[] children + { + get + { + return System.Array.ConvertAll(children_Internal, amg => (AudioMixerGroupController)amg); + } + set + { + children_Internal = System.Array.ConvertAll(value, amgc => (AudioMixerGroup)amgc); + } + } + + [NativeName("Children")] + private extern AudioMixerGroup[] children_Internal { get; set; } + + public extern AudioMixerEffectController[] effects { get; set; } + + public extern bool mute { get; set; } + public extern bool solo { get; set; } + public extern bool bypassEffects { get; set; } + } +} diff --git a/Modules/AudioEditor/ScriptBindings/AudioMixerSnapshotController.bindings.cs b/Modules/AudioEditor/ScriptBindings/AudioMixerSnapshotController.bindings.cs new file mode 100644 index 0000000000..f1855e0299 --- /dev/null +++ b/Modules/AudioEditor/ScriptBindings/AudioMixerSnapshotController.bindings.cs @@ -0,0 +1,42 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using UnityEngine; +using UnityEngine.Audio; +using UnityEngine.Bindings; + +namespace UnityEditor.Audio +{ + internal enum ParameterTransitionType + { + Lerp = 0, + Smoothstep = 1, + Squared = 2, + SquareRoot = 3, + BrickwallStart = 4, + BrickwallEnd = 5 + } + + [NativeHeader("Editor/Src/Audio/Mixer/AudioMixerSnapshotController.h")] + [NativeHeader("Modules/AudioEditor/ScriptBindings/AudioMixerSnapshotController.bindings.h")] + internal class AudioMixerSnapshotController : AudioMixerSnapshot + { + public AudioMixerSnapshotController(AudioMixer owner) + { + Internal_CreateAudioMixerSnapshotController(this, owner); + } + + [FreeFunction("AudioMixerSnapshotControllerBindings::Internal_CreateAudioMixerSnapshotController")] + private static extern void Internal_CreateAudioMixerSnapshotController([Writable] AudioMixerSnapshotController mono, AudioMixer owner); + + public extern GUID snapshotID { get; } + + public extern void SetValue(GUID guid, float value); + public extern bool GetValue(GUID guid, out float value); + + public extern void SetTransitionTypeOverride(GUID guid, ParameterTransitionType type); + public extern bool GetTransitionTypeOverride(GUID guid, out ParameterTransitionType type); + public extern void ClearTransitionTypeOverride(GUID guid); + } +} diff --git a/Modules/BuildPipeline/Editor/Managed/BuildSettings.cs b/Modules/BuildPipeline/Editor/Managed/BuildSettings.cs index b368c374e1..9eafb151b4 100644 --- a/Modules/BuildPipeline/Editor/Managed/BuildSettings.cs +++ b/Modules/BuildPipeline/Editor/Managed/BuildSettings.cs @@ -14,7 +14,8 @@ namespace UnityEditor.Build.Content public enum ContentBuildFlags { None = 0, - DisableWriteTypeTree = 1 << 0 + DisableWriteTypeTree = 1 << 0, + StripUnityVersion = 1 << 1 } [Serializable] diff --git a/Modules/BuildPipeline/Editor/Managed/ContentBuildInterface.bindings.cs b/Modules/BuildPipeline/Editor/Managed/ContentBuildInterface.bindings.cs index 51692ce6b9..d86456989c 100644 --- a/Modules/BuildPipeline/Editor/Managed/ContentBuildInterface.bindings.cs +++ b/Modules/BuildPipeline/Editor/Managed/ContentBuildInterface.bindings.cs @@ -98,8 +98,14 @@ public static WriteResult WriteSceneSerializedFile(string outputFolder, WriteSce static extern WriteResult WriteSceneSerializedFileAssetBundle(string outputFolder, string scenePath, WriteCommand writeCommand, BuildSettings settings, BuildUsageTagGlobal globalUsage, BuildUsageTagSet usageSet, BuildReferenceMap referenceMap, PreloadInfo preloadInfo, SceneBundleInfo sceneBundleInfo); + public static uint ArchiveAndCompress(ResourceFile[] resourceFiles, string outputBundlePath, + UnityEngine.BuildCompression compression) + { + return ArchiveAndCompress(resourceFiles, outputBundlePath, compression, false); + } + //modified to be thread safe - if called from a non-main thread, there are no dialogs presented in the case of an error. [ThreadSafe] - public static extern uint ArchiveAndCompress(ResourceFile[] resourceFiles, string outputBundlePath, UnityEngine.BuildCompression compression); + public static extern uint ArchiveAndCompress(ResourceFile[] resourceFiles, string outputBundlePath, UnityEngine.BuildCompression compression, bool stripUnityVersion); } } diff --git a/Modules/BuildPipeline/Editor/Shared/ReferencesArtifactGenerator.bindings.cs b/Modules/BuildPipeline/Editor/Shared/ReferencesArtifactGenerator.bindings.cs index baaacace58..cd00841d89 100644 --- a/Modules/BuildPipeline/Editor/Shared/ReferencesArtifactGenerator.bindings.cs +++ b/Modules/BuildPipeline/Editor/Shared/ReferencesArtifactGenerator.bindings.cs @@ -9,6 +9,7 @@ namespace UnityEditor { // AssetImporter for importing ReferenceArtifactGenerator [NativeHeader("Modules/AssetPipelineEditor/Public/ReferencesArtifactGenerator.h")] + [ExcludeFromPreset] internal partial class ReferencesArtifactGenerator : AssetImporter { } diff --git a/Modules/BuildReportingEditor/Managed/BuildFile.cs b/Modules/BuildReportingEditor/Managed/BuildFile.cs index 26b536c251..673cf09cae 100644 --- a/Modules/BuildReportingEditor/Managed/BuildFile.cs +++ b/Modules/BuildReportingEditor/Managed/BuildFile.cs @@ -10,7 +10,7 @@ namespace UnityEditor.Build.Reporting [NativeType(Header = "Modules/BuildReportingEditor/Public/BuildReport.h")] public struct BuildFile { - internal uint id { get; } + public uint id { get; } public string path { get; } public string role { get; } diff --git a/Modules/BuildReportingEditor/Managed/BuildReport.bindings.cs b/Modules/BuildReportingEditor/Managed/BuildReport.bindings.cs index 51f39c2419..0dabe5a70a 100644 --- a/Modules/BuildReportingEditor/Managed/BuildReport.bindings.cs +++ b/Modules/BuildReportingEditor/Managed/BuildReport.bindings.cs @@ -31,6 +31,11 @@ public StrippingInfo strippingInfo get { return GetAppendices().SingleOrDefault(); } } + public PackedAssets[] packedAssets + { + get { return GetAppendicesByType(); } + } + [NativeMethod("RelocateFiles")] internal extern void RecordFilesMoved(string originalPathPrefix, string newPathPrefix); @@ -64,6 +69,13 @@ internal TAppendix[] GetAppendices() where TAppendix : Object internal extern Object[] GetAppendices([NotNull] Type type); + internal TAppendix[] GetAppendicesByType() where TAppendix : Object + { + return GetAppendicesByType(typeof(TAppendix)).Cast().ToArray(); + } + + internal extern Object[] GetAppendicesByType([NotNull] Type type); + internal extern Object[] GetAllAppendices(); [FreeFunction("BuildReporting::GetLatestReport")] diff --git a/Modules/BuildReportingEditor/Managed/PackedAssetInfo.cs b/Modules/BuildReportingEditor/Managed/PackedAssetInfo.cs new file mode 100644 index 0000000000..843f2a5b33 --- /dev/null +++ b/Modules/BuildReportingEditor/Managed/PackedAssetInfo.cs @@ -0,0 +1,22 @@ +// 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 UnityEditor.Build.Reporting +{ + [NativeType(Header = "Modules/BuildReportingEditor/Public/PackedAssets.h")] + public struct PackedAssetInfo + { + [NativeName("fileID")] + public long id { get; } + public Type type { get; } + public ulong packedSize { get; } + public ulong offset { get; } + public GUID sourceAssetGUID { get; } + [NativeName("buildTimeAssetPath")] + public string sourceAssetPath { get; } + } +} diff --git a/Modules/BuildReportingEditor/Managed/PackedAssets.bindings.cs b/Modules/BuildReportingEditor/Managed/PackedAssets.bindings.cs new file mode 100644 index 0000000000..b206953e1f --- /dev/null +++ b/Modules/BuildReportingEditor/Managed/PackedAssets.bindings.cs @@ -0,0 +1,43 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using UnityEngine; +using UnityEngine.Bindings; +using Object = UnityEngine.Object; + +namespace UnityEditor.Build.Reporting +{ + [NativeType(Header = "Modules/BuildReportingEditor/Public/PackedAssets.h")] + [NativeClass("BuildReporting::PackedAssets")] + public sealed class PackedAssets : Object + { + public uint file + { + get { return GetFile(); } + } + + public string shortPath + { + get { return GetShortPath(); } + } + + public ulong overhead + { + get { return GetOverhead(); } + } + + public PackedAssetInfo[] contents + { + get { return GetContents(); } + } + + internal extern uint GetFile(); + + internal extern string GetShortPath(); + + internal extern ulong GetOverhead(); + + internal extern PackedAssetInfo[] GetContents(); + } +} diff --git a/Modules/DSPGraph/Public/ScriptBindings/AudioHandle.bindings.cs b/Modules/DSPGraph/Public/ScriptBindings/AudioHandle.bindings.cs index bc51a2ede3..fc8317eeb6 100644 --- a/Modules/DSPGraph/Public/ScriptBindings/AudioHandle.bindings.cs +++ b/Modules/DSPGraph/Public/ScriptBindings/AudioHandle.bindings.cs @@ -4,21 +4,68 @@ using System; +using System.Runtime.InteropServices; using UnityEngine.Bindings; using Unity.Collections.LowLevel.Unsafe; namespace Unity.Audio { [NativeType(Header = "Modules/DSPGraph/Public/DSPGraphHandles.h")] - internal struct Handle : IHandle + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct Handle : IHandle { [NativeDisableUnsafePtrRestriction] - public IntPtr Ptr; + 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 Ptr.Equals(other.Ptr) && Version == other.Version; + return m_Node == other.m_Node && Version == other.Version; } public override bool Equals(object obj) @@ -31,11 +78,22 @@ public override int GetHashCode() { unchecked { - return (Ptr.GetHashCode() * 397) ^ Version; + return ((int)m_Node * 397) ^ Version; } } - public bool Valid => Ptr != IntPtr.Zero; + 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/DSPCommandBlock.bindings.cs b/Modules/DSPGraph/Public/ScriptBindings/DSPCommandBlock.bindings.cs index be6add5afb..bf9059f528 100644 --- a/Modules/DSPGraph/Public/ScriptBindings/DSPCommandBlock.bindings.cs +++ b/Modules/DSPGraph/Public/ScriptBindings/DSPCommandBlock.bindings.cs @@ -72,6 +72,9 @@ public static extern void Internal_Disconnect(ref Handle graph, ref Handle block [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 index f606631ad5..beab6440d7 100644 --- a/Modules/DSPGraph/Public/ScriptBindings/DSPGraph.bindings.cs +++ b/Modules/DSPGraph/Public/ScriptBindings/DSPGraph.bindings.cs @@ -3,11 +3,24 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License -using System; +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 { @@ -44,6 +57,30 @@ public static extern uint Internal_AddNodeEventHandler( [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/DSPGraph/Public/ScriptBindings/DSPSampleProvider.bindings.cs b/Modules/DSPGraph/Public/ScriptBindings/DSPSampleProvider.bindings.cs index 9a0d3afd89..826e2d9655 100644 --- a/Modules/DSPGraph/Public/ScriptBindings/DSPSampleProvider.bindings.cs +++ b/Modules/DSPGraph/Public/ScriptBindings/DSPSampleProvider.bindings.cs @@ -3,7 +3,6 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License -using System; using UnityEngine.Bindings; namespace Unity.Audio @@ -12,22 +11,34 @@ namespace Unity.Audio 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); + 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); + 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); + 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/GraphViewEditor/EdgeControl.cs b/Modules/GraphViewEditor/EdgeControl.cs index b47b2d5563..ff11e04a71 100644 --- a/Modules/GraphViewEditor/EdgeControl.cs +++ b/Modules/GraphViewEditor/EdgeControl.cs @@ -157,6 +157,7 @@ public Color fromCapColor { m_FromCap.style.backgroundColor = m_FromCapColor; } + MarkDirtyRepaint(); } } @@ -174,6 +175,7 @@ public Color toCapColor { m_ToCap.style.backgroundColor = m_ToCapColor; } + MarkDirtyRepaint(); } } @@ -425,6 +427,7 @@ public virtual void UpdateLayout() m_ControlPointsDirty = false; } UpdateEdgeCaps(); + MarkDirtyRepaint(); } private List lastLocalControlPoints = new List(); @@ -913,129 +916,6 @@ void DrawEdge(MeshGenerationContext mgc) } } - private void RecomputeMesh() - { - int cpt = m_RenderPoints.Count; - - float polyLineLength = 0; - - for (int i = 1; i < cpt; ++i) - { - polyLineLength += (m_RenderPoints[i - 1] - m_RenderPoints[i]).sqrMagnitude; - } - - if (m_Mesh == null) - { - m_Mesh = new Mesh(); - m_Mesh.hideFlags = HideFlags.HideAndDontSave; - } - - Vector3[] vertices = m_Mesh.vertices; - Vector2[] uvs = m_Mesh.uv; - Vector3[] normals = m_Mesh.normals; - bool newIndices = false; - int wantedLength = (cpt) * 2; - if (vertices == null || vertices.Length != wantedLength) - { - vertices = new Vector3[wantedLength]; - uvs = new Vector2[wantedLength]; - normals = new Vector3[wantedLength]; - newIndices = true; - m_Mesh.triangles = new int[] {}; - } - - float halfWidth = edgeWidth * 0.5f; - - float vertexHalfWidth = halfWidth + 2; - - float currentLength = 0; - - Vector2 unitPreviousSegment = Vector2.zero; - for (int i = 0; i < cpt; ++i) - { - Vector2 dir; - Vector2 unitNextSegment = Vector2.zero; - Vector2 nextSegment = Vector2.zero; - - if (i < cpt - 1) - { - nextSegment = (m_RenderPoints[i + 1] - m_RenderPoints[i]); - unitNextSegment = nextSegment.normalized; - } - - - if (i > 0 && i < cpt - 1) - { - dir = unitPreviousSegment + unitNextSegment; - dir.Normalize(); - } - else if (i > 0) - { - dir = unitPreviousSegment; - } - else - { - dir = unitNextSegment; - } - - Vector2 norm = new Vector3(dir.y, -dir.x, 0); - - Vector2 border = -norm * vertexHalfWidth; - - int index = i * 2; - uvs[index] = new Vector2(-vertexHalfWidth, halfWidth); - vertices[index] = m_RenderPoints[i]; - // normals store the Vector2 normal in x,y and the progress in the edge in z ( which drive the gradient ). - normals[index] = new Vector3(-border.x, -border.y, currentLength / polyLineLength); - - uvs[index + 1] = new Vector2(vertexHalfWidth, halfWidth); - vertices[index + 1] = m_RenderPoints[i]; - normals[index + 1] = new Vector3(border.x, border.y, currentLength / polyLineLength); - - if (i < cpt - 2) - { - currentLength += nextSegment.sqrMagnitude; - } - else - { - currentLength = polyLineLength; - } - - unitPreviousSegment = unitNextSegment; - } - - m_Mesh.vertices = vertices; - m_Mesh.normals = normals; - m_Mesh.uv = uvs; - - if (newIndices) - { - //fill triangle indices as it is a triangle strip - int[] indices = new int[(wantedLength - 2) * 3]; - - for (int i = 0; i < wantedLength - 2; ++i) - { - int index = i * 3; - if ((i & 0x01) == 0) - { - indices[index] = i; - indices[index + 1] = i + 1; - indices[index + 2] = i + 2; - } - else - { - indices[index] = i + 1; - indices[index + 1] = i; - indices[index + 2] = i + 2; - } - } - - m_Mesh.triangles = indices; - } - - m_Mesh.RecalculateBounds(); - } - void OnLeavePanel(DetachFromPanelEvent e) { if (m_Mesh != null) diff --git a/Modules/GraphViewEditor/Elements/Blackboard/Blackboard.cs b/Modules/GraphViewEditor/Elements/Blackboard/Blackboard.cs index 45b85b8cf9..3341d75958 100644 --- a/Modules/GraphViewEditor/Elements/Blackboard/Blackboard.cs +++ b/Modules/GraphViewEditor/Elements/Blackboard/Blackboard.cs @@ -174,7 +174,6 @@ public Blackboard(GraphView associatedGraphView = null) hierarchy.Add(m_MainContainer); capabilities |= Capabilities.Movable | Capabilities.Resizable; - cacheAsBitmap = true; style.overflow = Overflow.Hidden; ClearClassList(); diff --git a/Modules/GraphViewEditor/Elements/Edge.cs b/Modules/GraphViewEditor/Elements/Edge.cs index 60ace69265..6b4bacab07 100644 --- a/Modules/GraphViewEditor/Elements/Edge.cs +++ b/Modules/GraphViewEditor/Elements/Edge.cs @@ -4,7 +4,6 @@ using UnityEngine; using UnityEngine.UIElements; -using UnityEngine.UIElements.StyleSheets; using UnityEngine.Profiling; namespace UnityEditor.Experimental.GraphView @@ -118,7 +117,6 @@ public Vector2 candidatePosition { edgeControl.from = m_GlobalCandidatePosition; } - MarkDirtyRepaint(); UpdateEdgeControl(); } } @@ -168,10 +166,9 @@ public Edge() this.AddManipulator(new EdgeManipulator()); this.AddManipulator(new ContextualMenuManipulator(null)); + RegisterCallback(OnEdgeAttach); RegisterCallback(OnGeometryChanged); AddStyleSheetPath("StyleSheets/GraphView/Edge.uss"); - - this.generateVisualContent += OnGenerateVisualContent; } public override bool Overlaps(Rect rectangle) @@ -198,6 +195,7 @@ public virtual void OnPortChanged(bool isInput) { edgeControl.outputOrientation = m_OutputPort?.orientation ?? (m_InputPort?.orientation ?? Orientation.Horizontal); edgeControl.inputOrientation = m_InputPort?.orientation ?? (m_OutputPort?.orientation ?? Orientation.Horizontal); + UpdateEdgeControl(); } internal bool ForceUpdateEdgeControl() @@ -217,58 +215,17 @@ public bool UpdateEdgeControl() if (m_GraphView == null) return false; - UpdateEndPoints(); + UpdateEdgeControlEndPoints(); edgeControl.UpdateLayout(); + UpdateEdgeControlColorsAndWidth(); return true; } - // This control is actually changing styles during drawing which is a bad habit - // The entire control should be reconstructed to assume the control as immutable - // during GenerateVisualContent. Would be good if this can be enforced by means of an exception, - // much like preventing adding controls during control removal callbacks - private void OnGenerateVisualContent(MeshGenerationContext mgc) - { - DrawEdge(); - } + protected virtual void DrawEdge() {} - protected override void OnCustomStyleResolved(ICustomStyle styles) + void UpdateEdgeControlColorsAndWidth() { - base.OnCustomStyleResolved(styles); - - int edgeWidthValue = 0; - Color selectColorValue = Color.clear; - Color edgeColorValue = Color.clear; - Color ghostColorValue = Color.clear; - - if (styles.TryGetValue(s_EdgeWidthProperty, out edgeWidthValue)) - m_EdgeWidth = edgeWidthValue; - - if (styles.TryGetValue(s_SelectedEdgeColorProperty, out selectColorValue)) - m_SelectedColor = selectColorValue; - - if (styles.TryGetValue(s_EdgeColorProperty, out edgeColorValue)) - m_DefaultColor = edgeColorValue; - - if (styles.TryGetValue(s_GhostEdgeColorProperty, out ghostColorValue)) - m_GhostColor = ghostColorValue; - } - - public override void OnSelected() - { - MarkDirtyRepaint(); - } - - public override void OnUnselected() - { - MarkDirtyRepaint(); - } - - protected virtual void DrawEdge() - { - if (!UpdateEdgeControl()) - return; - if (selected) { if (isGhostEdge) @@ -292,12 +249,20 @@ protected virtual void DrawEdge() if (m_OutputPort != null) m_OutputPort.UpdateCapColor(); - edgeControl.inputColor = m_InputPort == null ? m_OutputPort.portColor : m_InputPort.portColor; - edgeControl.outputColor = m_OutputPort == null ? m_InputPort.portColor : m_OutputPort.portColor; + if (m_InputPort != null) + edgeControl.inputColor = m_InputPort.portColor; + else if (m_OutputPort != null) + edgeControl.inputColor = m_OutputPort.portColor; + + if (m_OutputPort != null) + edgeControl.outputColor = m_OutputPort.portColor; + else if (m_InputPort != null) + edgeControl.outputColor = m_InputPort.portColor; + edgeControl.edgeWidth = edgeWidth; - edgeControl.toCapColor = m_InputPort == null ? m_OutputPort.portColor : m_InputPort.portColor; - edgeControl.fromCapColor = m_OutputPort == null ? m_InputPort.portColor : m_OutputPort.portColor; + edgeControl.toCapColor = edgeControl.inputColor; + edgeControl.fromCapColor = edgeControl.outputColor; if (isGhostEdge) { @@ -307,6 +272,40 @@ protected virtual void DrawEdge() } } + protected override void OnCustomStyleResolved(ICustomStyle styles) + { + base.OnCustomStyleResolved(styles); + + int edgeWidthValue = 0; + Color selectColorValue = Color.clear; + Color edgeColorValue = Color.clear; + Color ghostColorValue = Color.clear; + + if (styles.TryGetValue(s_EdgeWidthProperty, out edgeWidthValue)) + m_EdgeWidth = edgeWidthValue; + + if (styles.TryGetValue(s_SelectedEdgeColorProperty, out selectColorValue)) + m_SelectedColor = selectColorValue; + + if (styles.TryGetValue(s_EdgeColorProperty, out edgeColorValue)) + m_DefaultColor = edgeColorValue; + + if (styles.TryGetValue(s_GhostEdgeColorProperty, out ghostColorValue)) + m_GhostColor = ghostColorValue; + + UpdateEdgeControlColorsAndWidth(); + } + + public override void OnSelected() + { + UpdateEdgeControlColorsAndWidth(); + } + + public override void OnUnselected() + { + UpdateEdgeControlColorsAndWidth(); + } + protected virtual EdgeControl CreateEdgeControl() { return new EdgeControl @@ -346,6 +345,11 @@ void OnPortAttach(AttachToPanelEvent e) DoTrackGraphElement(port); } + void OnEdgeAttach(AttachToPanelEvent e) + { + UpdateEdgeControl(); + } + void UntrackGraphElement(Port port) { port.UnregisterCallback(OnPortAttach); @@ -412,23 +416,22 @@ private void OnPortGeometryChanged(GeometryChangedEvent evt) edgeControl.from = GetPortPosition(p); } } + + UpdateEdgeControl(); } private void OnGeometryChanged(GeometryChangedEvent evt) { - m_EndPointsDirty = true; - - //We make sure UpdateEdgeControl will be called - MarkDirtyRepaint(); + ForceUpdateEdgeControl(); } - private void UpdateEndPoints() + private void UpdateEdgeControlEndPoints() { if (!m_EndPointsDirty) { return; } - Profiler.BeginSample("Edge.UpdateEndPoints"); + Profiler.BeginSample("Edge.UpdateEdgeControlEndPoints"); m_GlobalCandidatePosition = this.WorldToLocal(m_CandidatePosition); if (m_OutputPort != null || m_InputPort != null) diff --git a/Modules/GraphViewEditor/Elements/Node.cs b/Modules/GraphViewEditor/Elements/Node.cs index cc81329400..cc786f8f07 100644 --- a/Modules/GraphViewEditor/Elements/Node.cs +++ b/Modules/GraphViewEditor/Elements/Node.cs @@ -332,7 +332,6 @@ public Node(string uiFile) if (borderContainer != null) { - borderContainer.cacheAsBitmap = true; borderContainer.style.overflow = Overflow.Hidden; mainContainer = borderContainer; var selection = main.Q(name: "selection-border"); diff --git a/Modules/GraphViewEditor/Elements/Port.cs b/Modules/GraphViewEditor/Elements/Port.cs index 24e6b9ac16..8ae9b24b0f 100644 --- a/Modules/GraphViewEditor/Elements/Port.cs +++ b/Modules/GraphViewEditor/Elements/Port.cs @@ -425,7 +425,11 @@ private void UpdateConnectorColorAndEnabledState() if (m_ConnectorBox == null) return; - m_ConnectorBox.style.borderColor = highlight ? m_PortColor : m_DisabledPortColor; + var color = highlight ? m_PortColor : m_DisabledPortColor; + m_ConnectorBox.style.borderLeftColor = color; + m_ConnectorBox.style.borderTopColor = color; + m_ConnectorBox.style.borderRightColor = color; + m_ConnectorBox.style.borderBottomColor = color; m_ConnectorBox.SetEnabled(highlight); } diff --git a/Modules/GraphViewEditor/Elements/Scope.cs b/Modules/GraphViewEditor/Elements/Scope.cs index 049ba99777..1c6831edf8 100644 --- a/Modules/GraphViewEditor/Elements/Scope.cs +++ b/Modules/GraphViewEditor/Elements/Scope.cs @@ -70,7 +70,6 @@ public Scope() ClearClassList(); AddToClassList("scope"); - cacheAsBitmap = true; style.overflow = Overflow.Hidden; style.position = Position.Absolute; diff --git a/Modules/GraphViewEditor/Manipulators/Resizer.cs b/Modules/GraphViewEditor/Manipulators/Resizer.cs index 69aa270ae0..9acbf1648e 100644 --- a/Modules/GraphViewEditor/Manipulators/Resizer.cs +++ b/Modules/GraphViewEditor/Manipulators/Resizer.cs @@ -70,7 +70,8 @@ void OnMouseDown(MouseDownEvent e) return; } - if (MouseCaptureController.IsMouseCaptured()) + IPanel panel = (e.target as VisualElement)?.panel; + if (panel.GetCapturingElement(PointerId.mousePointerId) != null) return; var ce = parent as GraphElement; diff --git a/Modules/GraphViewEditor/Manipulators/ShortcutHandler.cs b/Modules/GraphViewEditor/Manipulators/ShortcutHandler.cs index e893bae327..240b90914a 100644 --- a/Modules/GraphViewEditor/Manipulators/ShortcutHandler.cs +++ b/Modules/GraphViewEditor/Manipulators/ShortcutHandler.cs @@ -37,7 +37,8 @@ protected override void UnregisterCallbacksFromTarget() void OnKeyDown(KeyDownEvent evt) { - if (MouseCaptureController.IsMouseCaptured()) + IPanel panel = (evt.target as VisualElement)?.panel; + if (panel.GetCapturingElement(PointerId.mousePointerId) != null) return; if (m_Dictionary.ContainsKey(evt.imguiEvent)) diff --git a/Modules/GraphViewEditor/Manipulators/Zoomer.cs b/Modules/GraphViewEditor/Manipulators/Zoomer.cs index c0358b9d1c..f79377dca4 100644 --- a/Modules/GraphViewEditor/Manipulators/Zoomer.cs +++ b/Modules/GraphViewEditor/Manipulators/Zoomer.cs @@ -150,7 +150,8 @@ void OnWheel(WheelEvent evt) if (graphView == null) return; - if (MouseCaptureController.IsMouseCaptured()) + IPanel panel = (evt.target as VisualElement)?.panel; + if (panel.GetCapturingElement(PointerId.mousePointerId) != null) return; Vector3 position = graphView.viewTransform.position; diff --git a/Modules/GraphViewEditor/Views/GraphView.cs b/Modules/GraphViewEditor/Views/GraphView.cs index b45aab1ca6..72ced200bd 100644 --- a/Modules/GraphViewEditor/Views/GraphView.cs +++ b/Modules/GraphViewEditor/Views/GraphView.cs @@ -854,7 +854,7 @@ void OnKeyDownShortcut(KeyDownEvent evt) if (!isReframable) return; - if (MouseCaptureController.IsMouseCaptured()) + if (panel.GetCapturingElement(PointerId.mousePointerId) != null) return; EventPropagation result = EventPropagation.Continue; @@ -912,7 +912,7 @@ EventPropagation OnInsertNodeKeyDown(KeyDownEvent evt) internal void OnValidateCommand(ValidateCommandEvent evt) { - if (MouseCaptureController.IsMouseCaptured()) + if (panel.GetCapturingElement(PointerId.mousePointerId) != null) return; if ((evt.commandName == EventCommandNames.Copy && canCopySelection) @@ -945,7 +945,7 @@ public enum AskUser internal void OnExecuteCommand(ExecuteCommandEvent evt) { - if (MouseCaptureController.IsMouseCaptured()) + if (panel.GetCapturingElement(PointerId.mousePointerId) != null) return; if (evt.commandName == EventCommandNames.Copy) diff --git a/Modules/IMGUI/Event.bindings.cs b/Modules/IMGUI/Event.bindings.cs index fd3593010d..1711302709 100644 --- a/Modules/IMGUI/Event.bindings.cs +++ b/Modules/IMGUI/Event.bindings.cs @@ -15,6 +15,7 @@ partial class Event [NativeProperty("type", false, TargetType.Field)] public extern EventType rawType { get; } [NativeProperty("mousePosition", false, TargetType.Field)] public extern Vector2 mousePosition { get; set; } [NativeProperty("delta", false, TargetType.Field)] public extern Vector2 delta { get; set; } + [NativeProperty("pointerType", false, TargetType.Field)] public extern PointerType pointerType { get; set; } [NativeProperty("button", false, TargetType.Field)] public extern int button { get; set; } [NativeProperty("modifiers", false, TargetType.Field)] public extern EventModifiers modifiers { get; set; } [NativeProperty("pressure", false, TargetType.Field)] public extern float pressure { get; set; } diff --git a/Modules/IMGUI/Event.cs b/Modules/IMGUI/Event.cs index 81666b6b21..089dbb6c73 100644 --- a/Modules/IMGUI/Event.cs +++ b/Modules/IMGUI/Event.cs @@ -159,6 +159,19 @@ public bool isScrollWheel get { EventType t = type; return t == EventType.ScrollWheel; } } + // Is this event comes from a direct manipulation device? + // A direct manipulation device is a device where the user directly manipulates elements + // (like a touch screen), without any cursor acting as an intermediate. + internal bool isDirectManipulationDevice + { + [VisibleToOtherModules("UnityEngine.UIElementsModule")] + get + { + return pointerType == PointerType.Pen + || pointerType == PointerType.Touch; + } + } + // Create a keyboard event. public static Event KeyboardEvent(string key) { diff --git a/Modules/IMGUI/EventCommandNames.cs b/Modules/IMGUI/EventCommandNames.cs index 5595f506f8..0dc65449aa 100644 --- a/Modules/IMGUI/EventCommandNames.cs +++ b/Modules/IMGUI/EventCommandNames.cs @@ -18,6 +18,7 @@ internal static class EventCommandNames public const string DeselectAll = "DeselectAll"; public const string InvertSelection = "InvertSelection"; public const string Duplicate = "Duplicate"; + public const string Rename = "Rename"; public const string Delete = "Delete"; public const string SoftDelete = "SoftDelete"; public const string Find = "Find"; diff --git a/Modules/IMGUI/EventEnums.cs b/Modules/IMGUI/EventEnums.cs index b10736d878..a934285c0e 100644 --- a/Modules/IMGUI/EventEnums.cs +++ b/Modules/IMGUI/EventEnums.cs @@ -124,4 +124,11 @@ public enum EventModifiers // Function key FunctionKey = 64 } + + public enum PointerType + { + Mouse = 0, + Touch = 1, + Pen = 2, + } } diff --git a/Modules/IMGUI/GUI.cs b/Modules/IMGUI/GUI.cs index 6af7e349f4..7d5e9e846b 100644 --- a/Modules/IMGUI/GUI.cs +++ b/Modules/IMGUI/GUI.cs @@ -963,7 +963,7 @@ private static bool DoControl(Rect position, int id, bool on, bool hover, GUICon style.Draw(position, content, id, on, hover); break; case EventType.MouseDown: - if (position.Contains(evt.mousePosition)) + if (GUIUtility.HitTest(position, evt)) { GrabMouseControl(id); evt.Use(); @@ -983,7 +983,7 @@ private static bool DoControl(Rect position, int id, bool on, bool hover, GUICon { ReleaseMouseControl(); evt.Use(); - if (position.Contains(evt.mousePosition)) + if (GUIUtility.HitTest(position, evt)) { changed = true; return !on; @@ -1069,7 +1069,7 @@ private static int DoButtonGrid(Rect position, int selected, GUIContent[] conten switch (Event.current.GetTypeForControl(id)) { case EventType.MouseDown: - if (buttonRect.Contains(Event.current.mousePosition)) + if (GUIUtility.HitTest(buttonRect, Event.current)) { GUIUtility.hotControl = id; Event.current.Use(); diff --git a/Modules/IMGUI/GUIStyle.bindings.cs b/Modules/IMGUI/GUIStyle.bindings.cs index 8af2dddda3..32342543bd 100644 --- a/Modules/IMGUI/GUIStyle.bindings.cs +++ b/Modules/IMGUI/GUIStyle.bindings.cs @@ -26,7 +26,7 @@ partial class GUIStyleState [NativeHeader("IMGUIScriptingClasses.h")] partial class GUIStyle { - [NativeProperty("Name", false, TargetType.Function)] public extern string name { get; set; } + [NativeProperty("Name", false, TargetType.Function)] internal extern string rawName { get; set; } [NativeProperty("Font", false, TargetType.Function)] public extern Font font { get; set; } [NativeProperty("m_ImagePosition", false, TargetType.Field)] public extern ImagePosition imagePosition { get; set; } [NativeProperty("m_Alignment", false, TargetType.Field)] public extern TextAnchor alignment { get; set; } @@ -44,7 +44,6 @@ partial class GUIStyle [Obsolete("Don't use clipOffset - put things inside BeginGroup instead. This functionality will be removed in a later version.", false)] [NativeProperty("m_ClipOffset", false, TargetType.Field)] public extern Vector2 clipOffset { get; set; } [NativeProperty("m_ClipOffset", false, TargetType.Field)] internal extern Vector2 Internal_clipOffset { get; set; } - [FreeFunction(Name = "GUIStyle_Bindings::Internal_Create", IsThreadSafe = true)] private static extern IntPtr Internal_Create(GUIStyle self); [FreeFunction(Name = "GUIStyle_Bindings::Internal_Copy", IsThreadSafe = true)] private static extern IntPtr Internal_Copy(GUIStyle self, GUIStyle other); [FreeFunction(Name = "GUIStyle_Bindings::Internal_Destroy", IsThreadSafe = true)] private static extern void Internal_Destroy(IntPtr self); diff --git a/Modules/IMGUI/GUIStyle.cs b/Modules/IMGUI/GUIStyle.cs index 2b72cc0bb6..2a3c86689b 100644 --- a/Modules/IMGUI/GUIStyle.cs +++ b/Modules/IMGUI/GUIStyle.cs @@ -125,8 +125,23 @@ internal void InternalOnAfterDeserialize() [NonSerialized] RectOffset m_Border, m_Padding, m_Margin, m_Overflow; + [NonSerialized] + string m_Name; + // Internal callback used to override how gui styles are rendered. internal static DrawHandler onDraw; + // Cache StyleBlock ID + internal int blockId; + + public string name + { + get { return m_Name ?? (m_Name = rawName); } + set + { + m_Name = value; + rawName = value; + } + } // Rendering settings for when the component is displayed normally. public GUIStyleState normal diff --git a/Modules/IMGUI/GUIUtility.cs b/Modules/IMGUI/GUIUtility.cs index ddfc4c3915..08268a5516 100644 --- a/Modules/IMGUI/GUIUtility.cs +++ b/Modules/IMGUI/GUIUtility.cs @@ -327,6 +327,22 @@ public static Rect AlignRectToDevice(Rect rect) int width, height; return AlignRectToDevice(rect, out width, out height); } + + internal static bool HitTest(Rect rect, Vector2 point, int offset) + { + return (point.x >= rect.xMin - offset) && (point.x < rect.xMax + offset) && (point.y >= rect.yMin - offset) && (point.y < rect.yMax + offset); + } + + internal static bool HitTest(Rect rect, Vector2 point, bool isDirectManipulationDevice) + { + int offset = isDirectManipulationDevice ? 3 : 0; + return HitTest(rect, point, offset); + } + + internal static bool HitTest(Rect rect, Event evt) + { + return HitTest(rect, evt.mousePosition, evt.isDirectManipulationDevice); + } } [VisibleToOtherModules("UnityEngine.UIElementsModule")] diff --git a/Modules/IMGUI/SliderHandler.cs b/Modules/IMGUI/SliderHandler.cs index f1c49eac74..230070c7f6 100644 --- a/Modules/IMGUI/SliderHandler.cs +++ b/Modules/IMGUI/SliderHandler.cs @@ -72,15 +72,11 @@ private float OnMouseDown() { var mousePosition = CurrentEvent().mousePosition; - Rect thumbZone = ThumbSelectionRect(); - var mouseOverThumb = thumbZone.Contains(mousePosition); - - Rect clickableZone = thumbZone; - clickableZone.x = position.x; - clickableZone.width = position.width; + var thumbZone = ThumbSelectionRect(); + var mouseOverThumb = GUIUtility.HitTest(thumbZone, CurrentEvent()); // if the click is outside this control, just bail out... - if (IsEmptySlider() || (!mouseOverThumb && !clickableZone.Contains(mousePosition))) + if (IsEmptySlider() || (!GUIUtility.HitTest(position, CurrentEvent()) && !mouseOverThumb)) return currentValue; GUI.scrollTroughSide = 0; @@ -145,7 +141,7 @@ private float OnMouseUp() private float OnRepaint() { - bool hover = position.Contains(CurrentEvent().mousePosition); + bool hover = GUIUtility.HitTest(position, CurrentEvent()); slider.Draw(position, GUIContent.none, id, false, hover); if (!IsEmptySlider() && currentValue >= Mathf.Min(start, end) && currentValue <= Mathf.Max(start, end)) @@ -158,7 +154,7 @@ private float OnRepaint() if (GUIUtility.hotControl != id || !hover || IsEmptySlider()) return currentValue; - if (ThumbRect().Contains(CurrentEvent().mousePosition)) + if (GUIUtility.HitTest(ThumbRect(), CurrentEvent())) { if (GUI.scrollTroughSide != 0) // if was scrolling with "trough" and the thumb reached mouse - sliding action over { @@ -266,10 +262,7 @@ private SliderState SliderState() private Rect ThumbExtRect() { - var rect = new Rect(0, 0, thumbExtent.fixedWidth, thumbExtent.fixedHeight); - - rect.center = ThumbRect().center; - + var rect = new Rect(0, 0, thumbExtent.fixedWidth, thumbExtent.fixedHeight) {center = ThumbRect().center}; return rect; } diff --git a/Modules/IMGUI/TextEditor.cs b/Modules/IMGUI/TextEditor.cs index cddf994628..92650522ff 100644 --- a/Modules/IMGUI/TextEditor.cs +++ b/Modules/IMGUI/TextEditor.cs @@ -152,6 +152,12 @@ void GrabGraphicalCursorPos() // Looks up the platform-dependent key-action table & performs the event // return true if the event was recognized. public bool HandleKeyEvent(Event e) + { + return HandleKeyEvent(e, false); + } + + [VisibleToOtherModules] + internal bool HandleKeyEvent(Event e, bool textIsReadOnly) { InitKeyActions(); EventModifiers m = e.modifiers; @@ -159,7 +165,7 @@ public bool HandleKeyEvent(Event e) if (s_Keyactions.ContainsKey(e)) { TextEditOp op = (TextEditOp)s_Keyactions[e]; - PerformOperation(op); + PerformOperation(op, textIsReadOnly); e.modifiers = m; return true; } @@ -1126,7 +1132,7 @@ public void DrawCursor(string newText) m_Content.text = realText; } - bool PerformOperation(TextEditOp operation) + bool PerformOperation(TextEditOp operation, bool textIsReadOnly) { m_RevealCursor = true; @@ -1170,20 +1176,34 @@ bool PerformOperation(TextEditOp operation) case TextEditOp.SelectGraphicalLineEnd: SelectGraphicalLineEnd(); break; // case TextEditOp.SelectPageUp: return SelectPageUp (); break; // case TextEditOp.SelectPageDown: return SelectPageDown (); break; - case TextEditOp.Delete: return Delete(); - case TextEditOp.Backspace: return Backspace(); - case TextEditOp.Cut: return Cut(); + case TextEditOp.Delete: + if (textIsReadOnly) return false; + else return Delete(); + case TextEditOp.Backspace: + if (textIsReadOnly) return false; + else return Backspace(); + case TextEditOp.Cut: + if (textIsReadOnly) return false; + else return Cut(); case TextEditOp.Copy: Copy(); break; - case TextEditOp.Paste: return Paste(); + case TextEditOp.Paste: + if (textIsReadOnly) return false; + else return Paste(); case TextEditOp.SelectAll: SelectAll(); break; case TextEditOp.SelectNone: SelectNone(); break; // case TextEditOp.ScrollStart: return ScrollStart (); break; // case TextEditOp.ScrollEnd: return ScrollEnd (); break; // case TextEditOp.ScrollPageUp: return ScrollPageUp (); break; // case TextEditOp.ScrollPageDown: return ScrollPageDown (); break; - case TextEditOp.DeleteWordBack: return DeleteWordBack(); // break; // The uncoditional return makes the "break;" issue a warning about unreachable code - case TextEditOp.DeleteLineBack: return DeleteLineBack(); - case TextEditOp.DeleteWordForward: return DeleteWordForward(); // break; // The uncoditional return makes the "break;" issue a warning about unreachable code + case TextEditOp.DeleteWordBack: + if (textIsReadOnly) return false; + else return DeleteWordBack(); + case TextEditOp.DeleteLineBack: + if (textIsReadOnly) return false; + else return DeleteLineBack(); + case TextEditOp.DeleteWordForward: + if (textIsReadOnly) return false; + else return DeleteWordForward(); default: Debug.Log("Unimplemented: " + operation); break; diff --git a/Modules/PackageManager/Editor/Managed/PackageManifestImporterEditor.cs b/Modules/PackageManager/Editor/Managed/PackageManifestImporterEditor.cs index 078c437606..0b3e6d740d 100644 --- a/Modules/PackageManager/Editor/Managed/PackageManifestImporterEditor.cs +++ b/Modules/PackageManager/Editor/Managed/PackageManifestImporterEditor.cs @@ -127,9 +127,11 @@ private static class Styles protected override Type extraDataType => typeof(PackageManifestState); +#pragma warning disable 0649 [HideInInspector] [SerializeField] private Vector2 descriptionScrollViewPosition; +#pragma warning restore 0649 private List errorMessages; private List warningMessages; diff --git a/Modules/PackageManager/Editor/Managed/PackageTemplate.cs b/Modules/PackageManager/Editor/Managed/PackageTemplate.cs deleted file mode 100644 index a903440d93..0000000000 --- a/Modules/PackageManager/Editor/Managed/PackageTemplate.cs +++ /dev/null @@ -1,159 +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.CodeDom; -using System.CodeDom.Compiler; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using UnityEditorInternal; -using TemplateVariables = System.Collections.Generic.Dictionary; - -namespace UnityEditor.PackageManager -{ - internal static class PackageTemplate - { - private const string k_PackageManifestFileName = "package.json"; - - private static string ReplaceVariablesInString(TemplateVariables variables, string txt) - { - var result = txt; - foreach (var kvp in variables) - result = result.Replace($"#{kvp.Key}#", kvp.Value); - - return result; - } - - private static void ReplaceVariablesInFile(TemplateVariables variables, string file) - { - var original = File.ReadAllText(file); - var updated = ReplaceVariablesInString(variables, original); - - if (original != updated) - File.WriteAllText(file, updated); - } - - private static void RenameFileWithVariables(TemplateVariables variables, string file) - { - var originalFileName = Path.GetFileName(file); - var updatedFileName = ReplaceVariablesInString(variables, originalFileName); - - if (updatedFileName != originalFileName) - { - var folder = Path.GetDirectoryName(file); - FileUtil.MoveFileOrDirectory(file, Path.Combine(folder, updatedFileName)); - } - } - - private static IEnumerable GetPackageTemplateFiles(string templateFolder) - { - var packageManifestFile = Path.Combine(templateFolder, k_PackageManifestFileName); - if (!File.Exists(packageManifestFile)) - throw new Exception(string.Format(L10n.Tr("Package template must contain a file named {0}."), k_PackageManifestFileName)); - - var templateFiles = Directory.GetFiles(templateFolder, "*.*", SearchOption.AllDirectories); - foreach (var file in templateFiles) - { - if (Path.GetExtension(file) == ".meta") - throw new Exception(string.Format(L10n.Tr("Package template cannot contain meta files, [{0}] was found."), file)); - } - - return templateFiles; - } - - private static bool ValidateRootNamespace(string rootNamespace) - { - try - { - CodeGenerator.ValidateIdentifiers(new CodeNamespace(rootNamespace)); - return true; - } - catch (Exception) - { - return false; - } - } - - private static void ValidateOptions(PackageTemplateOptions options) - { - var errors = new List(); - var requiredErrorMessage = L10n.Tr("{0} is required"); - - options.name = options.name?.Trim(); - if (string.IsNullOrEmpty(options.name)) - errors.Add(string.Format(requiredErrorMessage, nameof(options.name))); - else if (!PackageValidation.ValidateName(options.name)) - errors.Add(string.Format(L10n.Tr("Package name [{0}] is invalid"), options.name)); - else if (PackageInfo.GetAll().Any(p => p.name == options.name)) - errors.Add(string.Format(L10n.Tr("The project already contains a package with the name [{0}]."), options.name)); - - options.displayName = options.displayName?.Trim(); - if (string.IsNullOrEmpty(options.displayName)) - errors.Add(string.Format(requiredErrorMessage, nameof(options.displayName))); - - options.rootNamespace = options.rootNamespace?.Trim(); - if (!string.IsNullOrEmpty(options.rootNamespace) && !ValidateRootNamespace(options.rootNamespace)) - errors.Add(string.Format(L10n.Tr("[{0}] is not a valid namespace"), options.rootNamespace)); - - options.templateFolder = options.templateFolder?.Trim(); - if (string.IsNullOrEmpty(options.templateFolder)) - errors.Add(string.Format(requiredErrorMessage, nameof(options.templateFolder))); - else if (!Directory.Exists(options.templateFolder)) - errors.Add(string.Format(L10n.Tr("The directory [{0}] does not exist"), options.templateFolder)); - - if (errors.Count > 0) - { - var invalidParamMsg = string.Format(L10n.Tr("{0} parameter is invalid"), nameof(options)); - var errorMsg = string.Join(Environment.NewLine, errors.ToArray()); - throw new ArgumentException($"{invalidParamMsg}:{Environment.NewLine}{errorMsg}"); - } - } - - private static TemplateVariables CreateTemplateVariables(PackageTemplateOptions options) - { - var version = InternalEditorUtility.GetUnityVersion(); - return new Dictionary - { - { "NAME", options.name }, - { "DISPLAYNAME", options.displayName }, - { "ROOTNAMESPACE", options.rootNamespace }, - { "UNITYVERSION", $"{version.Major}.{version.Minor}" }, - }; - } - - public static string CreatePackage(PackageTemplateOptions options) - { - ValidateOptions(options); - - var targetFolder = $"{Folders.GetPackagesPath()}/{options.name}"; - if (Directory.Exists(targetFolder)) - throw new InvalidOperationException(string.Format(L10n.Tr("The target folder [{0}] for this new package already exists."), targetFolder)); - - var variables = CreateTemplateVariables(options); - var templateFolder = options.templateFolder; - var tempFolder = FileUtil.GetUniqueTempPathInProject(); - try - { - FileUtil.CopyFileOrDirectory(templateFolder, tempFolder); - - foreach (var file in GetPackageTemplateFiles(tempFolder)) - { - File.SetAttributes(file, File.GetAttributes(file) & ~FileAttributes.ReadOnly); - ReplaceVariablesInFile(variables, file); - RenameFileWithVariables(variables, file); - } - - Directory.Move(tempFolder, targetFolder); - } - finally - { - if (Directory.Exists(tempFolder)) - Directory.Delete(tempFolder, true); - } - - return targetFolder; - } - } -} diff --git a/Modules/PackageManager/Editor/Managed/PackageTemplateOptions.cs b/Modules/PackageManager/Editor/Managed/PackageTemplateOptions.cs deleted file mode 100644 index f2a5ec7484..0000000000 --- a/Modules/PackageManager/Editor/Managed/PackageTemplateOptions.cs +++ /dev/null @@ -1,19 +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 UnityEditor; -using System.IO; - -namespace UnityEditor.PackageManager -{ - internal class PackageTemplateOptions - { - private static string DefaultTemplateFolder { get; } = Path.Combine(EditorApplication.applicationContentsPath, "Resources/PackageManager/PackageTemplates/default"); - - public string name { get; set; } - public string displayName { get; set; } - public string rootNamespace { get; set; } - public string templateFolder { get; set; } = DefaultTemplateFolder; - } -} diff --git a/Modules/PackageManagerUI/Editor/External/SemVersion.cs b/Modules/PackageManagerUI/Editor/External/SemVersion.cs index 3f5008719b..40fb5016e7 100644 --- a/Modules/PackageManagerUI/Editor/External/SemVersion.cs +++ b/Modules/PackageManagerUI/Editor/External/SemVersion.cs @@ -3,7 +3,7 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License /* -Copyright (c) 2013 Max Hauser +Copyright (c) 2013 Max Hauser Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -66,6 +66,7 @@ private SemVersion(SerializationInfo info, StreamingContext context) Build = semVersion.Build; } + /// /// Initializes a new instance of the class. /// @@ -87,7 +88,7 @@ public SemVersion(int major, int minor = 0, int patch = 0, string prerelease = " /// /// Initializes a new instance of the class. /// - /// The that is used to initialize + /// The that is used to initialize /// the Major, Minor, Patch and Build properties. public SemVersion(Version version) { @@ -133,7 +134,7 @@ public static SemVersion Parse(string version, bool strict = false) var minorMatch = match.Groups["minor"]; int minor = 0; - if (minorMatch.Success) + if (minorMatch.Success) { minor = int.Parse(minorMatch.Value, CultureInfo.InvariantCulture); } @@ -148,7 +149,7 @@ public static SemVersion Parse(string version, bool strict = false) { patch = int.Parse(patchMatch.Value, CultureInfo.InvariantCulture); } - else if (strict) + else if (strict) { throw new InvalidOperationException("Invalid version (no patch version given in strict mode)"); } @@ -163,8 +164,8 @@ public static SemVersion Parse(string version, bool strict = false) /// Parses the specified string to a semantic version. /// /// The version string. - /// When the method returns, contains a SemVersion instance equivalent - /// to the version string passed in, if the version string was valid, or null if the + /// When the method returns, contains a SemVersion instance equivalent + /// to the version string passed in, if the version string was valid, or null if the /// version string was not valid. /// If set to true minor and patch version are required, else they default to 0. /// False when a invalid version string is passed, otherwise true. @@ -210,7 +211,7 @@ public static int Compare(SemVersion versionA, SemVersion versionB) } /// - /// Make a copy of the current instance with optional altered fields. + /// Make a copy of the current instance with optional altered fields. /// /// The major version. /// The minor version. @@ -286,15 +287,15 @@ public override string ToString() } /// - /// Compares the current instance with another object of the same type and returns an integer that indicates - /// whether the current instance precedes, follows, or occurs in the same position in the sort order as the + /// Compares the current instance with another object of the same type and returns an integer that indicates + /// whether the current instance precedes, follows, or occurs in the same position in the sort order as the /// other object. /// /// An object to compare with this instance. /// - /// A value that indicates the relative order of the objects being compared. - /// The return value has these meanings: Value Meaning Less than zero - /// This instance precedes in the sort order. + /// A value that indicates the relative order of the objects being compared. + /// The return value has these meanings: Value Meaning Less than zero + /// This instance precedes in the sort order. /// Zero This instance occurs in the same position in the sort order as . i /// Greater than zero This instance follows in the sort order. /// @@ -304,15 +305,15 @@ public int CompareTo(object obj) } /// - /// Compares the current instance with another object of the same type and returns an integer that indicates - /// whether the current instance precedes, follows, or occurs in the same position in the sort order as the + /// Compares the current instance with another object of the same type and returns an integer that indicates + /// whether the current instance precedes, follows, or occurs in the same position in the sort order as the /// other object. /// /// An object to compare with this instance. /// - /// A value that indicates the relative order of the objects being compared. - /// The return value has these meanings: Value Meaning Less than zero - /// This instance precedes in the sort order. + /// A value that indicates the relative order of the objects being compared. + /// The return value has these meanings: Value Meaning Less than zero + /// This instance precedes in the sort order. /// Zero This instance occurs in the same position in the sort order as . i /// Greater than zero This instance follows in the sort order. /// @@ -344,8 +345,8 @@ public bool PrecedenceMatches(SemVersion other) /// /// The semantic version. /// - /// A value that indicates the relative order of the objects being compared. - /// The return value has these meanings: Value Meaning Less than zero + /// A value that indicates the relative order of the objects being compared. + /// The return value has these meanings: Value Meaning Less than zero /// This instance precedes in the version precedence. /// Zero This instance has the same precedence as . i /// Greater than zero This instance has creater precedence as . @@ -440,7 +441,7 @@ public override bool Equals(object obj) /// Returns a hash code for this instance. /// /// - /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. /// public override int GetHashCode() { @@ -462,6 +463,7 @@ public void GetObjectData(SerializationInfo info, StreamingContext context) info.AddValue("SemVersion", ToString()); } + /// /// Implicit conversion from string to SemVersion. /// @@ -473,67 +475,67 @@ public static implicit operator SemVersion(string version) } /// - /// The override of the equals operator. + /// The override of the equals operator. /// /// The left value. /// The right value. /// If left is equal to right true, else false. - public static bool operator ==(SemVersion left, SemVersion right) + public static bool operator==(SemVersion left, SemVersion right) { return SemVersion.Equals(left, right); } /// - /// The override of the un-equal operator. + /// The override of the un-equal operator. /// /// The left value. /// The right value. /// If left is not equal to right true, else false. - public static bool operator !=(SemVersion left, SemVersion right) + public static bool operator!=(SemVersion left, SemVersion right) { return !SemVersion.Equals(left, right); } /// - /// The override of the greater operator. + /// The override of the greater operator. /// /// The left value. /// The right value. /// If left is greater than right true, else false. - public static bool operator >(SemVersion left, SemVersion right) + public static bool operator>(SemVersion left, SemVersion right) { return SemVersion.Compare(left, right) > 0; } /// - /// The override of the greater than or equal operator. + /// The override of the greater than or equal operator. /// /// The left value. /// The right value. /// If left is greater than or equal to right true, else false. - public static bool operator >=(SemVersion left, SemVersion right) + public static bool operator>=(SemVersion left, SemVersion right) { return left == right || left > right; } /// - /// The override of the less operator. + /// The override of the less operator. /// /// The left value. /// The right value. /// If left is less than right true, else false. - public static bool operator <(SemVersion left, SemVersion right) + public static bool operator<(SemVersion left, SemVersion right) { return SemVersion.Compare(left, right) < 0; } /// - /// The override of the less than or equal operator. + /// The override of the less than or equal operator. /// /// The left value. /// The right value. /// If left is less than or equal to right true, else false. - public static bool operator <=(SemVersion left, SemVersion right) + public static bool operator<=(SemVersion left, SemVersion right) { return left == right || left < right; } diff --git a/Modules/PackageManagerUI/Editor/Services/Analytics/PackageManagerWindowAnalytics.cs b/Modules/PackageManagerUI/Editor/Services/Analytics/PackageManagerWindowAnalytics.cs new file mode 100644 index 0000000000..885a9b41d4 --- /dev/null +++ b/Modules/PackageManagerUI/Editor/Services/Analytics/PackageManagerWindowAnalytics.cs @@ -0,0 +1,53 @@ +// 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.Text.RegularExpressions; + +namespace UnityEditor.PackageManager.UI +{ + [Serializable] + internal struct PackageManagerWindowAnalytics + { + public string action; + public string package_id; + public string search_text; + public string filter_name; + public bool window_docked; + public bool dependencies_visible; + public bool preview_visible; + public long t_since_start; // in microseconds + public long ts; // in milliseconds + + public static void Setup() + { + int maxEventsPerHour = 1000; + int maxNumberOfElementInStruct = 100; + string vendorKey = "unity.package-manager-ui"; + + EditorAnalytics.RegisterEventWithLimit("packageManagerWindowUserAction", maxEventsPerHour, maxNumberOfElementInStruct, vendorKey); + } + + public static void SendEvent(string action, string packageId = null) + { + // remove sensitive part of the id: file path or url is not tracked + if (!string.IsNullOrEmpty(packageId)) + packageId = Regex.Replace(packageId, "(?[^@]+)@(?[^:]+):.+", "${package}@${protocol}"); + + var parameters = new PackageManagerWindowAnalytics + { + action = action, + package_id = packageId ?? string.Empty, + search_text = PackageFiltering.instance.currentSearchText, + filter_name = PackageFiltering.instance.currentFilterTab.ToString(), + window_docked = EditorWindow.GetWindowDontShow()?.docked ?? false, + dependencies_visible = PackageManagerPrefs.instance.showPackageDependencies, + preview_visible = PackageManagerPrefs.instance.showPreviewPackages, + t_since_start = (long)(EditorApplication.timeSinceStartup * 1E6), + ts = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond + }; + EditorAnalytics.SendEventWithLimit("packageManagerWindowUserAction", parameters); + } + }; +} diff --git a/Modules/PackageManagerUI/Editor/Services/AssetStore/ASyncHTTPClientFactory.cs b/Modules/PackageManagerUI/Editor/Services/AssetStore/ASyncHTTPClientFactory.cs new file mode 100644 index 0000000000..938307a285 --- /dev/null +++ b/Modules/PackageManagerUI/Editor/Services/AssetStore/ASyncHTTPClientFactory.cs @@ -0,0 +1,13 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +namespace UnityEditor.PackageManager.UI.AssetStore +{ + internal class ASyncHTTPClientFactory : IASyncHTTPClientFactory + { + public IAsyncHTTPClient GetASyncHTTPClient(string url) => new AsyncHTTPClient(url); + + public IAsyncHTTPClient GetASyncHTTPClient(string url, string method) => new AsyncHTTPClient(url, method); + } +} diff --git a/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreCache.cs b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreCache.cs new file mode 100644 index 0000000000..f8531ddd65 --- /dev/null +++ b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreCache.cs @@ -0,0 +1,104 @@ +// 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 UnityEditor.Utils; +using UnityEngine; + +namespace UnityEditor.PackageManager.UI.AssetStore +{ + internal sealed class AssetStoreCache + { + static IAssetStoreCache s_Instance = null; + public static IAssetStoreCache instance => s_Instance ?? AssetStoreCacheInternal.instance; + + [Serializable] + [FilePathAttribute("Asset Store/Cache/AssetStore.cache", FilePathAttribute.Location.AppDataFolder)] + internal class AssetStoreCacheInternal : ScriptableSingleton, IAssetStoreCache, ISerializationCallbackReceiver + { + private Dictionary m_ProductETags = new Dictionary(); + + [NonSerialized] + internal bool m_IsModified; + + [SerializeField] + private long[] m_SerializedIds = new long[0]; + + [SerializeField] + private string[] m_SerializedETags = new string[0]; + + public void OnBeforeSerialize() + { + m_SerializedIds = m_ProductETags.Keys.ToArray(); + m_SerializedETags = m_ProductETags.Values.ToArray(); + } + + public void OnAfterDeserialize() + { + for (var i = 0; i < m_SerializedIds.Length; i++) + { + m_ProductETags[m_SerializedIds[i]] = m_SerializedETags[i]; + } + } + + private void OnDisable() + { + if (m_IsModified) + { + Save(true); + m_IsModified = false; + } + } + + public string GetLastETag(long productId) + { + return m_ProductETags.ContainsKey(productId) ? m_ProductETags[productId] : string.Empty; + } + + public void SetLastETag(long productId, string etag) + { + var lastEtag = GetLastETag(productId); + if (etag != lastEtag) + { + m_ProductETags[productId] = etag; + m_IsModified = true; + } + } + + public Texture2D LoadImage(long productId, string url) + { + if (string.IsNullOrEmpty(url)) + return null; + + var hash = Hash128.Compute(url); + var path = Paths.Combine(ApplicationUtil.instance.userAppDataPath, "Asset Store", "Cache", "Images", productId.ToString(), hash.ToString()); + if (File.Exists(path)) + { + var texture = new Texture2D(2, 2); + if (texture.LoadImage(File.ReadAllBytes(path))) + return texture; + } + + return null; + } + + public void SaveImage(long productId, string url, Texture2D texture) + { + if (string.IsNullOrEmpty(url) || texture == null) + return; + + var path = Paths.Combine(ApplicationUtil.instance.userAppDataPath, "Asset Store", "Cache", "Images", productId.ToString()); + if (!Directory.Exists(path)) + Directory.CreateDirectory(path); + + var hash = Hash128.Compute(url); + path = Paths.Combine(path, hash.ToString()); + File.WriteAllBytes(path, texture.EncodeToJPG()); + } + } + } +} diff --git a/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreClient.cs b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreClient.cs new file mode 100644 index 0000000000..03faf25f5c --- /dev/null +++ b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreClient.cs @@ -0,0 +1,640 @@ +// 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 UnityEngine; +using AssetStorePackageInfo = UnityEditor.PackageInfo; + +namespace UnityEditor.PackageManager.UI.AssetStore +{ + internal sealed class AssetStoreClient + { + static IAssetStoreClient s_Instance = null; + public static IAssetStoreClient instance => s_Instance ?? AssetStoreClientInternal.instance; + + [Serializable] + internal class AssetStoreClientInternal : ScriptableSingleton, IAssetStoreClient, ISerializationCallbackReceiver + { + private static readonly string k_AssetStoreDownloadPrefix = "content__"; + + public event Action> onPackagesChanged = delegate {}; + public event Action onDownloadProgress = delegate {}; + + public event Action onListOperationStart = delegate {}; + public event Action onListOperationFinish = delegate {}; + public event Action onOperationError = delegate {}; + + public event Action onProductListFetched = delegate {}; + public event Action onProductFetched = delegate {}; + + public event Action onFetchDetailsStart = delegate {}; + public event Action onFetchDetailsFinish = delegate {}; + + private Dictionary m_Downloads = new Dictionary(); + + private Dictionary m_UpdateDetails = new Dictionary(); + + private HashSet m_PackageDetailsFetched = new HashSet(); + + [SerializeField] + private string[] m_SerializedUpdateDetailKeys = new string[0]; + + [SerializeField] + private PackageState[] m_SerializedUpdateDetailValues = new PackageState[0]; + + [SerializeField] + private DownloadProgress[] m_SerializedDownloads = new DownloadProgress[0]; + + [SerializeField] + private long[] m_SerializedPackageDetailsFetched; + + [SerializeField] + private bool m_SetupDone; + + public void OnAfterDeserialize() + { + m_Downloads.Clear(); + foreach (var p in m_SerializedDownloads) + { + m_Downloads[p.packageId] = p; + } + + m_UpdateDetails.Clear(); + for (var i = 0; i < m_SerializedUpdateDetailKeys.Length; i++) + { + m_UpdateDetails[m_SerializedUpdateDetailKeys[i]] = m_SerializedUpdateDetailValues[i]; + } + + m_PackageDetailsFetched = new HashSet(m_SerializedPackageDetailsFetched); + } + + public void OnBeforeSerialize() + { + m_SerializedDownloads = m_Downloads.Values.ToArray(); + + m_SerializedUpdateDetailKeys = new string[m_UpdateDetails.Count]; + m_SerializedUpdateDetailValues = new PackageState[m_UpdateDetails.Count]; + var i = 0; + foreach (var kp in m_UpdateDetails) + { + m_SerializedUpdateDetailKeys[i] = kp.Key; + m_SerializedUpdateDetailValues[i] = kp.Value; + i++; + } + + m_SerializedPackageDetailsFetched = m_PackageDetailsFetched.ToArray(); + } + + public void Fetch(long productId) + { + if (!ApplicationUtil.instance.isUserLoggedIn) + { + onOperationError?.Invoke(new Error(NativeErrorCode.Unknown, L10n.Tr("User not logged in"))); + return; + } + + var id = productId.ToString(); + var localPackages = GetLocalPackages(); + if (localPackages.ContainsKey(id)) + RefreshProductUpdateDetails(new Dictionary { { id, localPackages[id] } }, () => { FetchInternal(localPackages, productId); }); + else + FetchInternal(localPackages, productId); + } + + private void FetchInternal(IDictionary localPackages, long productID) + { + // create a placeholder before fetching data from the cloud for the first time + if (!m_PackageDetailsFetched.Contains(productID)) + { + onPackagesChanged?.Invoke(new[] { new PlaceholderPackage(productID.ToString(), PackageTag.AssetStore) }); + } + + FetchDetailsInternal(new[] { productID }, localPackages); + + onProductFetched?.Invoke(productID); + } + + public void List(int offset, int limit, string searchText = "", bool fetchDetails = true) + { + if (!ApplicationUtil.instance.isUserLoggedIn) + { + onOperationError?.Invoke(new Error(NativeErrorCode.Unknown, L10n.Tr("User not logged in"))); + return; + } + + onListOperationStart?.Invoke(); + + var localPackages = GetLocalPackages(); + if (offset == 0) + RefreshProductUpdateDetails(localPackages, () => { ListInternal(localPackages, offset, limit, searchText, fetchDetails); }); + else + ListInternal(localPackages, offset, limit, searchText, fetchDetails); + } + + private void ListInternal(IDictionary localPackages, int offset, int limit, string searchText, bool fetchDetails) + { + AssetStoreRestAPI.instance.GetProductIDList(offset, limit, searchText, productList => + { + if (!productList.isValid) + { + onListOperationFinish?.Invoke(); + onOperationError?.Invoke(new Error(NativeErrorCode.Unknown, productList.errorMessage)); + return; + } + + if (!ApplicationUtil.instance.isUserLoggedIn) + { + productList.total = 0; + productList.list.Clear(); + } + + onProductListFetched?.Invoke(productList, fetchDetails); + + if (productList.list.Count == 0) + { + onListOperationFinish?.Invoke(); + return; + } + + var placeholderPackages = new List(); + + foreach (var product in productList.list) + { + // create a placeholder before fetching data from the cloud for the first time + if (!m_PackageDetailsFetched.Contains(product)) + placeholderPackages.Add(new PlaceholderPackage(product.ToString(), PackageTag.AssetStore)); + } + + if (placeholderPackages.Any()) + onPackagesChanged?.Invoke(placeholderPackages); + + onListOperationFinish?.Invoke(); + + if (fetchDetails) + FetchDetailsInternal(productList.list, localPackages); + }); + } + + public void FetchDetails(IEnumerable packageIds) + { + FetchDetailsInternal(packageIds, GetLocalPackages()); + } + + private void FetchDetailsInternal(IEnumerable packageIds, IDictionary localPackages) + { + var countProduct = packageIds.Count(); + if (countProduct == 0) + return; + + onFetchDetailsStart?.Invoke(); + + foreach (var id in packageIds) + { + AssetStoreRestAPI.instance.GetProductDetail(id, productDetail => + { + AssetStorePackage package; + object error; + if (!productDetail.TryGetValue("errorMessage", out error)) + { + AssetStorePackageInfo localPackage; + if (localPackages.TryGetValue(id.ToString(), out localPackage)) + { + productDetail["localPath"] = localPackage.packagePath; + } + else + { + productDetail["localPath"] = string.Empty; + } + + package = new AssetStorePackage(id.ToString(), productDetail); + if (m_UpdateDetails.ContainsKey(package.uniqueId)) + { + package.SetState(m_UpdateDetails[package.uniqueId]); + } + + if (package.state == PackageState.Outdated && !string.IsNullOrEmpty(localPackage.packagePath)) + { + package.m_FetchedVersion.localPath = string.Empty; + + try + { + var info = new AssetStorePackageVersion.SpecificVersionInfo(); + var item = Json.Deserialize(localPackage.jsonInfo) as Dictionary; + info.versionId = item["version_id"] as string; + info.versionString = item["version"] as string; + info.publishedDate = item["pubdate"] as string; + info.supportedVersion = item["unity_version"] as string; + + var installedVersion = new AssetStorePackageVersion(id.ToString(), productDetail, info); + installedVersion.localPath = localPackage.packagePath; + + package.AddVersion(installedVersion); + } + catch (Exception) + { + } + } + m_PackageDetailsFetched.Add(id); + } + else + package = new AssetStorePackage(id.ToString(), new Error(NativeErrorCode.Unknown, error as string)); + + onPackagesChanged?.Invoke(new[] { package }); + + countProduct--; + if (countProduct == 0) + onFetchDetailsFinish?.Invoke(); + }); + } + } + + public void Refresh(IEnumerable packages) + { + if (packages == null || !packages.Any() || !ApplicationUtil.instance.isUserLoggedIn) + return; + + var localInfos = new Dictionary(); + var localPackages = AssetStoreUtils.instance.GetLocalPackageList(); + foreach (var p in localPackages) + { + if (!string.IsNullOrEmpty(p.jsonInfo)) + { + var item = Json.Deserialize(p.jsonInfo) as Dictionary; + if (item != null && item.ContainsKey("id") && item["id"] is string) + { + localInfos[(string)item["id"]] = new AssetStorePackageVersion.SpecificVersionInfo + { + packagePath = p.packagePath, + versionString = item.ContainsKey("version") && item["version"] is string? (string)item["version"] : string.Empty, + versionId = item.ContainsKey("version_id") && item["version_id"] is string? (string)item["version_id"] : string.Empty, + publishedDate = item.ContainsKey("pubdate") && item["pubdate"] is string? (string)item["pubdate"] : string.Empty, + supportedVersion = item.ContainsKey("unity_version") && item["unity_version"] is string? (string)item["unity_version"] : string.Empty + }; + } + } + } + + var updatedPackages = new List(); + foreach (var package in packages) + { + var assetStorePackage = package as AssetStorePackage; + if (assetStorePackage == null) + continue; + + AssetStorePackageVersion.SpecificVersionInfo localInfo; + localInfos.TryGetValue(assetStorePackage.uniqueId, out localInfo); + + var packageChanged = false; + if (localInfo == null) + { + if (assetStorePackage.installedVersion != null) + { + assetStorePackage.m_FetchedVersion.localPath = string.Empty; + if (assetStorePackage.m_FetchedVersion != assetStorePackage.m_LocalVersion) + { + assetStorePackage.RemoveVersion(assetStorePackage.m_LocalVersion); + } + + assetStorePackage.SetState(PackageState.UpToDate); + packageChanged = true; + } + } + else if (assetStorePackage.installedVersion == null || localInfo.versionString != assetStorePackage.installedVersion.versionString) + { + if (assetStorePackage.m_FetchedVersion.versionString == localInfo.versionString) + { + assetStorePackage.m_FetchedVersion.localPath = localInfo.packagePath; + if (assetStorePackage.m_LocalVersion != assetStorePackage.m_FetchedVersion) + { + assetStorePackage.RemoveVersion(assetStorePackage.m_LocalVersion); + } + + assetStorePackage.SetState(PackageState.UpToDate); + } + else if (assetStorePackage.m_LocalVersion.versionString == localInfo.versionString) + { + assetStorePackage.m_FetchedVersion.localPath = string.Empty; + assetStorePackage.m_LocalVersion.localPath = localInfo.packagePath; + assetStorePackage.SetState(PackageState.Outdated); + } + else + { + assetStorePackage.m_FetchedVersion.localPath = string.Empty; + assetStorePackage.AddVersion(new AssetStorePackageVersion(assetStorePackage.m_FetchedVersion, localInfo)); + assetStorePackage.m_LocalVersion.localPath = localInfo.packagePath; + assetStorePackage.SetState(PackageState.Outdated); + } + + packageChanged = true; + } + + if (packageChanged) + { + if (m_UpdateDetails.ContainsKey(assetStorePackage.uniqueId)) + m_UpdateDetails[assetStorePackage.uniqueId] = assetStorePackage.state; + + updatedPackages.Add(package); + } + } + + if (updatedPackages.Any()) + onPackagesChanged?.Invoke(updatedPackages); + } + + public void Refresh(IPackage package) + { + if (!ApplicationUtil.instance.isUserLoggedIn) + return; + + var assetStorePackage = package as AssetStorePackage; + if (assetStorePackage == null) + return; + + AssetStorePackageVersion.SpecificVersionInfo localInfo = null; + var localPackage = AssetStoreUtils.instance.GetLocalPackageList().FirstOrDefault(p => + { + if (!string.IsNullOrEmpty(p.jsonInfo)) + { + var item = Json.Deserialize(p.jsonInfo) as Dictionary; + if (item != null && item.ContainsKey("id") && item["id"] is string && package.uniqueId == (string)item["id"]) + { + localInfo = new AssetStorePackageVersion.SpecificVersionInfo + { + versionString = item.ContainsKey("version") && item["version"] is string? (string)item["version"] : string.Empty, + versionId = item.ContainsKey("version_id") && item["version_id"] is string? (string)item["version_id"] : string.Empty, + publishedDate = item.ContainsKey("pubdate") && item["pubdate"] is string? (string)item["pubdate"] : string.Empty, + supportedVersion = item.ContainsKey("unity_version") && item["unity_version"] is string? (string)item["unity_version"] : string.Empty + }; + return true; + } + } + return false; + }); + + var packageChanged = false; + if (localInfo == null) + { + if (assetStorePackage.installedVersion != null) + { + assetStorePackage.m_FetchedVersion.localPath = string.Empty; + if (assetStorePackage.m_FetchedVersion != assetStorePackage.m_LocalVersion) + { + assetStorePackage.RemoveVersion(assetStorePackage.m_LocalVersion); + } + + assetStorePackage.SetState(PackageState.UpToDate); + packageChanged = true; + } + } + else if (assetStorePackage.installedVersion == null || localInfo.versionString != assetStorePackage.installedVersion.versionString) + { + if (assetStorePackage.m_FetchedVersion.versionString == localInfo.versionString) + { + assetStorePackage.m_FetchedVersion.localPath = localPackage.packagePath; + if (assetStorePackage.m_LocalVersion != assetStorePackage.m_FetchedVersion) + { + assetStorePackage.RemoveVersion(assetStorePackage.m_LocalVersion); + } + assetStorePackage.SetState(PackageState.UpToDate); + } + else if (assetStorePackage.m_LocalVersion.versionString == localInfo.versionString) + { + assetStorePackage.m_FetchedVersion.localPath = string.Empty; + assetStorePackage.m_LocalVersion.localPath = localPackage.packagePath; + assetStorePackage.SetState(PackageState.Outdated); + } + else + { + assetStorePackage.m_FetchedVersion.localPath = string.Empty; + assetStorePackage.AddVersion(new AssetStorePackageVersion(assetStorePackage.m_FetchedVersion, localInfo)); + assetStorePackage.m_LocalVersion.localPath = localPackage.packagePath; + assetStorePackage.SetState(PackageState.Outdated); + } + + packageChanged = true; + } + + if (packageChanged) + { + if (m_UpdateDetails.ContainsKey(assetStorePackage.uniqueId)) + m_UpdateDetails[assetStorePackage.uniqueId] = assetStorePackage.state; + onPackagesChanged?.Invoke(new[] { package }); + } + } + + public bool IsAnyDownloadInProgress() + { + return m_Downloads.Values.Any(progress => progress.state == DownloadProgress.State.InProgress || progress.state == DownloadProgress.State.Started); + } + + private static string AssetStoreCompatibleKey(string packageId) + { + if (packageId.StartsWith(k_AssetStoreDownloadPrefix)) + return packageId; + + return k_AssetStoreDownloadPrefix + packageId; + } + + public bool IsDownloadInProgress(string packageId) + { + DownloadProgress progress; + if (!GetDownloadProgress(packageId, out progress)) + return false; + + return progress.state == DownloadProgress.State.InProgress || progress.state == DownloadProgress.State.Started; + } + + public bool GetDownloadProgress(string packageId, out DownloadProgress progress) + { + progress = null; + return m_Downloads.TryGetValue(AssetStoreCompatibleKey(packageId), out progress); + } + + public void Download(string packageId) + { + DownloadProgress progress; + if (GetDownloadProgress(packageId, out progress)) + { + if (progress.state != DownloadProgress.State.Started && + progress.state != DownloadProgress.State.InProgress && + progress.state != DownloadProgress.State.Decrypting) + { + m_Downloads.Remove(AssetStoreCompatibleKey(packageId)); + } + else + { + onDownloadProgress?.Invoke(progress); + return; + } + } + + progress = new DownloadProgress(packageId); + m_Downloads[AssetStoreCompatibleKey(packageId)] = progress; + onDownloadProgress?.Invoke(progress); + + var id = long.Parse(packageId); + AssetStoreDownloadOperation.instance.DownloadUnityPackageAsync(id, result => + { + progress.state = result.downloadState; + if (result.downloadState == DownloadProgress.State.Error) + progress.message = result.errorMessage; + + onDownloadProgress?.Invoke(progress); + }); + } + + public void AbortDownload(string packageId) + { + DownloadProgress progress; + if (!GetDownloadProgress(packageId, out progress)) + return; + + if (progress.state == DownloadProgress.State.Aborted || progress.state == DownloadProgress.State.Completed || progress.state == DownloadProgress.State.Error) + return; + + var id = long.Parse(packageId); + AssetStoreDownloadOperation.instance.AbortDownloadPackageAsync(id, result => + { + progress.state = DownloadProgress.State.Aborted; + progress.current = progress.total; + progress.message = L10n.Tr("Download aborted"); + + onDownloadProgress?.Invoke(progress); + + m_Downloads.Remove(AssetStoreCompatibleKey(packageId)); + }); + } + + // Used by AssetStoreUtils + public void OnDownloadProgress(string packageId, string message, ulong bytes, ulong total) + { + DownloadProgress progress; + if (!GetDownloadProgress(packageId, out progress)) + { + if (packageId.StartsWith(k_AssetStoreDownloadPrefix)) + packageId = packageId.Substring(k_AssetStoreDownloadPrefix.Length); + progress = new DownloadProgress(packageId) { state = DownloadProgress.State.InProgress, message = "downloading" }; + m_Downloads[AssetStoreCompatibleKey(packageId)] = progress; + } + + progress.current = bytes; + progress.total = total; + progress.message = message; + + if (message == "ok") + progress.state = DownloadProgress.State.Completed; + else if (message == "connecting") + progress.state = DownloadProgress.State.Started; + else if (message == "downloading") + progress.state = DownloadProgress.State.InProgress; + else if (message == "decrypt") + progress.state = DownloadProgress.State.Decrypting; + else if (message == "aborted") + progress.state = DownloadProgress.State.Aborted; + else + progress.state = DownloadProgress.State.Error; + + onDownloadProgress?.Invoke(progress); + } + + public void Setup() + { + System.Diagnostics.Debug.Assert(!m_SetupDone); + m_SetupDone = true; + + ApplicationUtil.instance.onUserLoginStateChange += OnUserLoginStateChange; + if (ApplicationUtil.instance.isUserLoggedIn) + { + AssetStoreUtils.instance.RegisterDownloadDelegate(this); + } + } + + public void Clear() + { + System.Diagnostics.Debug.Assert(m_SetupDone); + m_SetupDone = false; + + AssetStoreUtils.instance.UnRegisterDownloadDelegate(this); + ApplicationUtil.instance.onUserLoginStateChange -= OnUserLoginStateChange; + } + + public void Reset() + { + m_UpdateDetails.Clear(); + m_PackageDetailsFetched.Clear(); + } + + private void OnUserLoginStateChange(bool loggedIn) + { + if (!loggedIn) + { + AssetStoreUtils.instance.UnRegisterDownloadDelegate(this); + AbortAllDownloads(); + } + else + { + AssetStoreUtils.instance.RegisterDownloadDelegate(this); + } + } + + public void AbortAllDownloads() + { + var currentDownloads = m_Downloads.Values.Where(v => v.state == DownloadProgress.State.Started || v.state == DownloadProgress.State.InProgress) + .Select(v => long.Parse(v.packageId)).ToArray(); + m_Downloads.Clear(); + + foreach (var download in currentDownloads) + AssetStoreDownloadOperation.instance.AbortDownloadPackageAsync(download); + } + + private void RefreshProductUpdateDetails(IDictionary localPackages, Action doneCallbackAction) + { + var needsUpdateDetail = localPackages.Where(kp => m_UpdateDetails[kp.Key] == PackageState.UpToDate); + if (!needsUpdateDetail.Any()) + { + doneCallbackAction?.Invoke(); + } + else + { + var list = needsUpdateDetail.Select(kp => kp.Value).ToList(); + AssetStoreRestAPI.instance.GetProductUpdateDetail(list, updateDetails => + { + object error; + if (!updateDetails.TryGetValue("errorMessage", out error)) + { + var results = updateDetails["results"] as List; + foreach (var item in results) + { + var updateDetail = item as IDictionary; + var canUpdate = (updateDetail["can_update"] is long? (long)updateDetail["can_update"] : 0) != 0; + m_UpdateDetails[updateDetail["id"] as string] = canUpdate ? PackageState.Outdated : PackageState.UpToDate; + } + } + + doneCallbackAction?.Invoke(); + }); + } + } + + private IDictionary GetLocalPackages() + { + var localPackages = new Dictionary(); + foreach (var package in AssetStoreUtils.instance.GetLocalPackageList()) + { + var item = Json.Deserialize(package.jsonInfo) as Dictionary; + if (item != null && item.ContainsKey("id") && item["id"] is string) + { + var packageId = (string)item["id"]; + localPackages[packageId] = package; + if (!m_UpdateDetails.ContainsKey(packageId)) + m_UpdateDetails[packageId] = PackageState.UpToDate; + } + } + return localPackages; + } + } + } +} diff --git a/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreDownloadOperation.cs b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreDownloadOperation.cs new file mode 100644 index 0000000000..73e6a8947b --- /dev/null +++ b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreDownloadOperation.cs @@ -0,0 +1,164 @@ +// 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.Text.RegularExpressions; +using UnityEngine; + +namespace UnityEditor.PackageManager.UI.AssetStore +{ + internal sealed class AssetStoreDownloadOperation + { + static IDownloadOperation s_Instance = null; + public static IDownloadOperation instance => s_Instance ?? AssetStoreDownloadOperationInternal.instance; + + [Serializable] + internal class AssetStoreDownloadOperationInternal : IDownloadOperation + { + private static AssetStoreDownloadOperationInternal s_Instance; + public static AssetStoreDownloadOperationInternal instance => s_Instance ?? (s_Instance = new AssetStoreDownloadOperationInternal()); + + private static Texture2D s_MissingTexture; + + private IASyncHTTPClientFactory m_AsyncHTTPClient; + + private AssetStoreDownloadOperationInternal() + { + m_AsyncHTTPClient = new ASyncHTTPClientFactory(); + } + + public void DownloadImageAsync(long productID, string url, Action doneCallbackAction = null) + { + if (s_MissingTexture == null) + { + s_MissingTexture = (Texture2D)EditorGUIUtility.LoadRequired("Icons/UnityLogo.png"); + } + + var texture = AssetStoreCache.instance.LoadImage(productID, url); + if (texture != null) + { + doneCallbackAction?.Invoke(productID, texture); + return; + } + + var httpRequest = m_AsyncHTTPClient.GetASyncHTTPClient(url); + httpRequest.doneCallback = httpClient => + { + if (httpClient.IsSuccess() && httpClient.texture != null) + { + AssetStoreCache.instance.SaveImage(productID, url, httpClient.texture); + doneCallbackAction?.Invoke(productID, httpClient.texture); + return; + } + + doneCallbackAction?.Invoke(productID, s_MissingTexture); + }; + httpRequest.Begin(); + } + + public void AbortDownloadPackageAsync(long productID, Action doneCallbackAction = null) + { + var ret = new DownloadResult(); + + AssetStoreRestAPI.instance.GetDownloadDetail(productID, downloadInformation => + { + if (!downloadInformation.isValid) + { + ret.downloadState = DownloadProgress.State.Error; + ret.errorMessage = downloadInformation.errorMessage; + doneCallbackAction?.Invoke(ret); + return; + } + + string[] dest = { downloadInformation.PublisherName, downloadInformation.CategoryName, downloadInformation.PackageName }; + var res = AssetStoreUtils.instance.AbortDownload($"content__{productID}", dest); + ret.downloadState = res ? DownloadProgress.State.Aborted : DownloadProgress.State.Error; + if (!res) + { + ret.errorMessage = "Cannot abort download."; + } + + doneCallbackAction?.Invoke(ret); + }); + } + + public void DownloadUnityPackageAsync(long productID, Action doneCallbackAction = null) + { + AssetStoreRestAPI.instance.GetDownloadDetail(productID, downloadInfo => + { + var ret = new DownloadResult(); + if (!downloadInfo.isValid) + { + ret.downloadState = DownloadProgress.State.Error; + ret.errorMessage = downloadInfo.errorMessage; + doneCallbackAction?.Invoke(ret); + return; + } + + string[] dest = + { + downloadInfo.PublisherName.Replace(".", ""), + downloadInfo.CategoryName.Replace(".", ""), + downloadInfo.PackageName.Replace(".", "") + }; + + var json = AssetStoreUtils.instance.CheckDownload( + $"content__{downloadInfo.PackageId}", + downloadInfo.Url, dest, + downloadInfo.Key); + + var resumeOK = false; + try + { + json = Regex.Replace(json, "\"url\":(?\"?[^,]+\"?),\"", "\"url\":\"${url}\",\""); + json = Regex.Replace(json, "\"key\":(?\"?[0-9a-zA-Z]*\"?)\\}", "\"key\":\"${key}\"}"); + json = Regex.Replace(json, "\"+(?[^\"]+)\"+", "\"${value}\""); + + var current = Json.Deserialize(json) as IDictionary; + if (current == null) + { + throw new ArgumentException("Invalid JSON"); + } + + var inProgress = current.ContainsKey("in_progress") && (current["in_progress"] is bool? (bool)current["in_progress"] : false); + if (inProgress) + { + ret.downloadState = DownloadProgress.State.InProgress; + doneCallbackAction?.Invoke(ret); + return; + } + + if (current.ContainsKey("download") && current["download"] is IDictionary) + { + var download = (IDictionary)current["download"]; + var existingUrl = download.ContainsKey("url") ? download["url"] as string : string.Empty; + var existingKey = download.ContainsKey("key") ? download["key"] as string : string.Empty; + resumeOK = (existingUrl == downloadInfo.Url && existingKey == downloadInfo.Key); + } + } + catch (Exception e) + { + ret.downloadState = DownloadProgress.State.Error; + ret.errorMessage = e.Message; + doneCallbackAction?.Invoke(ret); + return; + } + + json = $"{{\"download\":{{\"url\":\"{downloadInfo.Url}\",\"key\":\"{downloadInfo.Key}\"}}}}"; + AssetStoreUtils.instance.Download( + $"content__{downloadInfo.PackageId}", + downloadInfo.Url, + dest, + downloadInfo.Key, + json, + resumeOK); + + ret.downloadState = DownloadProgress.State.Started; + doneCallbackAction?.Invoke(ret); + }); + } + } + } +} diff --git a/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreOAuth.cs b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreOAuth.cs new file mode 100644 index 0000000000..6647877b61 --- /dev/null +++ b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreOAuth.cs @@ -0,0 +1,394 @@ +// 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 UnityEditor.Connect; + +namespace UnityEditor.PackageManager.UI.AssetStore +{ + internal class AssetStoreOAuth + { + static IAssetStoreOAuth s_Instance = null; + public static IAssetStoreOAuth instance { get { return s_Instance ?? AssetStoreOAuthInternal.instance; } } + + public class AssetStoreToken + { + private const long k_BufferTime = 15L; // We make sure we still have 15 seconds with the token + + public string access_token; + public string expires_in + { + get + { + return m_ExpirationIn.ToString(); + } + set + { + m_ExpirationIn = long.Parse(value); + m_ExpirationStart = EpochSeconds; + } + } + + private double m_ExpirationStart; + private long m_ExpirationIn; + + private static double EpochSeconds => (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; + + public AssetStoreToken() + { + m_ExpirationIn = 0; + m_ExpirationStart = EpochSeconds; + } + + public bool IsValid(long bufferTime = k_BufferTime) + { + return m_ExpirationIn > 0 && (EpochSeconds - m_ExpirationStart) < (m_ExpirationIn - bufferTime); + } + } + + public class AccessToken : AssetStoreToken + { + public string token_type; + public string refresh_token; + public string user; + public string display_name; + } + + public class TokenInfo : AssetStoreToken + { + public string sub; + public string scopes; + public string client_id; + public string ip_address; + } + + public class UserInfo + { + public string id; + public string username; + public string defaultOrganization; + + private bool m_IsValid; + public bool isValid + { + get + { + return m_IsValid && accessToken != null && accessToken.IsValid() && tokenInfo != null && tokenInfo.IsValid(); + } + set + { + m_IsValid = value; + } + } + + public string errorMessage; + public AccessToken accessToken; + public TokenInfo tokenInfo; + public string authCode; + } + + private class AssetStoreOAuthInternal : ScriptableSingleton, IAssetStoreOAuth + { + private string m_Host = ""; + private string m_Secret = ""; + private const string kOAuthUri = "/v1/oauth2/token"; + private const string kTokenInfoUri = "/v1/oauth2/tokeninfo"; + private const string kUserInfoUri = "/v1/users"; + private const string kServiceId = "packman"; + + private IAsyncHTTPClient m_UserInfoRequest; + private IAsyncHTTPClient m_AccessTokenRequest; + private IAsyncHTTPClient m_TokenRequest; + + private IASyncHTTPClientFactory m_AsyncHTTPClient; + + private UserInfo m_UserInfo; + private List> m_DoneCallbackList; + + private AssetStoreOAuthInternal() + { + m_UserInfo = new UserInfo(); + m_UserInfo.isValid = false; + m_DoneCallbackList = new List>(); + m_AsyncHTTPClient = new ASyncHTTPClientFactory(); + } + + public void OnEnable() + { + if (string.IsNullOrEmpty(m_Secret)) + { + m_Secret = UnityConnect.instance.GetConfigurationURL(CloudConfigUrl.CloudPackagesKey); + } + + if (string.IsNullOrEmpty(m_Host)) + { + m_Host = UnityConnect.instance.GetConfigurationURL(CloudConfigUrl.CloudIdentity); + } + + if (ApplicationUtil.instance.isUserLoggedIn) + GetAuthCode(); + + ApplicationUtil.instance.onUserLoginStateChange += OnUserLoginStateChange; + } + + private void OnDisable() + { + ApplicationUtil.instance.onUserLoginStateChange -= OnUserLoginStateChange; + } + + private void OnUserLoginStateChange(bool loggedIn) + { + m_UserInfo = new UserInfo(); + + m_AuthCodeRequested = false; + m_TokenRequest?.Abort(); + m_UserInfoRequest?.Abort(); + m_AccessTokenRequest?.Abort(); + + if (loggedIn) + { + GetAuthCode(); + } + } + + public void FetchUserInfo(Action doneCallbackInfo) + { + if (m_UserInfo.isValid) + doneCallbackInfo?.Invoke(m_UserInfo); + else + { + if (doneCallbackInfo != null) + m_DoneCallbackList.Add(doneCallbackInfo); + GetAuthCode(); + } + } + + private void OnDoneFetchUserInfo() + { + var currList = m_DoneCallbackList; + m_DoneCallbackList = new List>(); + for (int i = 0; i < currList.Count; i++) + currList[i].Invoke(m_UserInfo); + } + + private bool m_AuthCodeRequested; + + private void GetAuthCode() + { + if (!string.IsNullOrEmpty(m_UserInfo.authCode)) + { + GetAccessToken(); + return; + } + if (m_AuthCodeRequested) + { + return; + // a request is already running, no need to recall + } + + m_AuthCodeRequested = true; + try + { + UnityOAuth.GetAuthorizationCodeAsync(kServiceId, authCodeResponse => + { + if (authCodeResponse.AuthCode != null) + { + m_UserInfo.authCode = authCodeResponse.AuthCode; + GetAccessToken(); + } + else + { + m_UserInfo.authCode = ""; + m_UserInfo.errorMessage = authCodeResponse.Exception.ToString(); + OnDoneFetchUserInfo(); + } + m_AuthCodeRequested = false; + }); + } + catch (Exception e) + { + m_UserInfo.authCode = ""; + m_UserInfo.errorMessage = e.Message; + OnDoneFetchUserInfo(); + m_AuthCodeRequested = false; + } + } + + private void GetAccessToken() + { + if (string.IsNullOrEmpty(m_UserInfo.authCode)) + { + GetAuthCode(); + return; + } + if (m_UserInfo.accessToken != null && m_UserInfo.accessToken.IsValid()) + { + GetTokenInfo(); + return; + } + if (m_AccessTokenRequest != null) + { + return; + // a request is already running, no need to recall + } + m_AccessTokenRequest = m_AsyncHTTPClient.GetASyncHTTPClient($"{m_Host}{kOAuthUri}", "POST"); + m_AccessTokenRequest.postData = $"grant_type=authorization_code&code={m_UserInfo.authCode}&client_id=packman&client_secret={m_Secret}&redirect_uri=packman://unity"; + m_AccessTokenRequest.header["Content-Type"] = "application/x-www-form-urlencoded"; + m_AccessTokenRequest.doneCallback = httpClient => + { + if (httpClient.IsSuccess()) + { + var res = Json.Deserialize(httpClient.text) as Dictionary; + if (res != null) + { + var accessTokenResponse = new AccessToken(); + accessTokenResponse.access_token = res["access_token"] as string; + accessTokenResponse.token_type = res["token_type"] as string; + accessTokenResponse.expires_in = res["expires_in"] as string; + accessTokenResponse.refresh_token = res["refresh_token"] as string; + accessTokenResponse.user = res["user"] as string; + accessTokenResponse.display_name = res["display_name"] as string; + m_UserInfo.accessToken = accessTokenResponse; + if (m_UserInfo.accessToken.IsValid()) + GetTokenInfo(); + else + { + m_UserInfo.errorMessage = "Access token invalid"; + OnDoneFetchUserInfo(); + } + } + else + { + m_UserInfo.errorMessage = "Failed to parse JSON."; + m_UserInfo.accessToken = null; + OnDoneFetchUserInfo(); + } + } + else + { + m_UserInfo.errorMessage = httpClient.text; + m_UserInfo.accessToken = null; + OnDoneFetchUserInfo(); + } + m_AccessTokenRequest = null; + }; + m_AccessTokenRequest.Begin(); + } + + private void GetTokenInfo() + { + if (m_UserInfo.accessToken == null || !m_UserInfo.accessToken.IsValid()) + { + GetAccessToken(); + return; + } + if (m_UserInfo.tokenInfo != null && m_UserInfo.tokenInfo.IsValid()) + { + GetUserInfo(); + return; + } + if (m_TokenRequest != null) + { + return; + // a request is already running, no need to recall + } + + m_TokenRequest = m_AsyncHTTPClient.GetASyncHTTPClient($"{m_Host}{kTokenInfoUri}?access_token={m_UserInfo.accessToken.access_token}"); + m_TokenRequest.doneCallback = httpClient => + { + if (httpClient.IsSuccess()) + { + var res = Json.Deserialize(httpClient.text) as Dictionary; + if (res != null) + { + var tokenInfo = new TokenInfo(); + tokenInfo.sub = res["sub"] as string; + tokenInfo.scopes = res["scopes"] as string; + tokenInfo.expires_in = res["expires_in"] as string; + tokenInfo.client_id = res["client_id"] as string; + tokenInfo.ip_address = res["ip_address"] as string; + tokenInfo.access_token = res["access_token"] as string; + m_UserInfo.tokenInfo = tokenInfo; + if (m_UserInfo.tokenInfo.IsValid()) + GetUserInfo(); + else + { + m_UserInfo.errorMessage = "TokenInfo invalid"; + OnDoneFetchUserInfo(); + } + } + else + { + m_UserInfo.errorMessage = "Failed to parse JSON."; + m_UserInfo.tokenInfo = null; + OnDoneFetchUserInfo(); + } + } + else + { + m_UserInfo.errorMessage = httpClient.text; + m_UserInfo.tokenInfo = null; + OnDoneFetchUserInfo(); + } + m_TokenRequest = null; + }; + m_TokenRequest.Begin(); + } + + private void GetUserInfo() + { + if (m_UserInfo.accessToken == null || !m_UserInfo.accessToken.IsValid()) + { + GetAccessToken(); + return; + } + if (m_UserInfo.tokenInfo == null || !m_UserInfo.tokenInfo.IsValid()) + { + GetTokenInfo(); + return; + } + if (m_UserInfoRequest != null) + { + return; + // a request is already running, no need to recall + } + + m_UserInfoRequest = m_AsyncHTTPClient.GetASyncHTTPClient($"{m_Host}{kUserInfoUri}/{m_UserInfo.tokenInfo.sub}"); + m_UserInfoRequest.header["Authorization"] = "Bearer " + m_UserInfo.accessToken.access_token; + m_UserInfoRequest.doneCallback = httpClient => + { + if (httpClient.IsSuccess()) + { + var res = Json.Deserialize(httpClient.text) as Dictionary; + if (res != null) + { + m_UserInfo.id = res["id"] as string; + m_UserInfo.username = res["username"] as string; + var extended = res["extendedProperties"] as Dictionary; + m_UserInfo.defaultOrganization = extended["UNITY_DEFAULT_ORGANIZATION"] as string; + m_UserInfo.isValid = true; + m_UserInfo.errorMessage = ""; + OnDoneFetchUserInfo(); + } + else + { + m_UserInfo.isValid = false; + m_UserInfo.errorMessage = "Failed to parse JSON."; + OnDoneFetchUserInfo(); + } + } + else + { + m_UserInfo.isValid = false; + m_UserInfo.errorMessage = httpClient.text; + OnDoneFetchUserInfo(); + } + m_UserInfoRequest = null; + }; + m_UserInfoRequest.Begin(); + } + } + } +} diff --git a/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStorePackage.cs b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStorePackage.cs new file mode 100644 index 0000000000..b4c71e64f8 --- /dev/null +++ b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStorePackage.cs @@ -0,0 +1,103 @@ +// 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 UnityEngine; + +namespace UnityEditor.PackageManager.UI.AssetStore +{ + [Serializable] + internal class AssetStorePackage : IPackage + { + [SerializeField] + private string m_ProductId; + + public string name => string.Empty; + public string uniqueId => m_ProductId; + + public string displayName => m_Versions.FirstOrDefault()?.displayName; + + [SerializeField] + private List m_Versions; + + internal AssetStorePackageVersion m_InstalledVersion => m_Versions.FirstOrDefault(pv => pv.isAvailableOnDisk); + internal AssetStorePackageVersion m_FetchedVersion => m_Versions.FirstOrDefault(); + internal AssetStorePackageVersion m_LocalVersion => m_Versions.LastOrDefault(); + + public IEnumerable versions => m_Versions.Cast(); + public IEnumerable keyVersions => m_Versions.Cast(); + public IPackageVersion installedVersion => m_InstalledVersion; + public IPackageVersion latestVersion => m_FetchedVersion; + public IPackageVersion latestPatch => latestVersion; + public IPackageVersion recommendedVersion => latestVersion; + public IPackageVersion primaryVersion => installedVersion ?? latestVersion; + + [SerializeField] + private PackageState m_State; + public PackageState state => m_State; + + public void SetState(PackageState state) + { + m_State = state; + } + + public bool isDiscoverable => true; + + [SerializeField] + private List m_Errors; + public IEnumerable errors => m_Errors; + + public void AddError(Error error) + { + m_Errors?.Add(error); + } + + public void ClearErrors() + { + m_Errors?.Clear(); + } + + public void AddVersion(AssetStorePackageVersion version) + { + m_Versions.Add(version); + } + + public void RemoveVersion(AssetStorePackageVersion version) + { + m_Versions.Remove(version); + } + + public AssetStorePackage(string productId, Error error) + { + m_Errors = new List { error }; + m_State = PackageState.Error; + m_ProductId = productId; + m_Versions = new List(); + } + + public AssetStorePackage(string productId, IDictionary productDetail) + { + m_Errors = new List(); + m_State = PackageState.UpToDate; + m_ProductId = productId; + m_Versions = new List(); + try + { + m_Versions.Add(new AssetStorePackageVersion(productId, productDetail)); + } + catch (Exception e) + { + m_Errors.Add(new Error(NativeErrorCode.Unknown, e.Message)); + m_State = PackageState.Error; + } + } + + public IPackage Clone() + { + return (IPackage)MemberwiseClone(); + } + } +} diff --git a/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStorePackageVersion.cs b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStorePackageVersion.cs new file mode 100644 index 0000000000..fdd7c3d4d7 --- /dev/null +++ b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStorePackageVersion.cs @@ -0,0 +1,459 @@ +// 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 System.Text.RegularExpressions; +using UnityEngine; + +namespace UnityEditor.PackageManager.UI.AssetStore +{ + [Serializable] + internal class AssetStorePackageVersion : IPackageVersion + { + public class SpecificVersionInfo + { + public string versionString; + public string versionId; + public string publishedDate; + public string supportedVersion; + public string packagePath; + } + + [SerializeField] + private string m_PackageUniqueId; + [SerializeField] + private string m_DisplayName; + [SerializeField] + private string m_Type; + [SerializeField] + private string m_Author; + [SerializeField] + private string m_Description; + [SerializeField] + private string m_Category; + [SerializeField] + private List m_Errors; + [SerializeField] + private SemVersion m_Version; + [SerializeField] + private DateTime m_PublishedDate; + [SerializeField] + private string m_PublisherId; + [SerializeField] + private bool m_IsAvailableOnDisk; + [SerializeField] + private string m_LocalPath; + [SerializeField] + private string m_VersionString; + [SerializeField] + private string m_VersionId; + [SerializeField] + private List m_SupportedUnityVersions; + [SerializeField] + private SemVersion m_SupportedUnityVersion; + [SerializeField] + private List m_Images; + [SerializeField] + private List m_SizeInfos; + [SerializeField] + private List m_Links; + [SerializeField] + private PackageTag m_Tag; + + public string name => string.Empty; + + public string displayName => m_DisplayName; + + public string type => m_Type; + + public string author => m_Author; + + public string description => m_Description; + + public string category => m_Category; + + public string packageUniqueId => m_PackageUniqueId; + + public string uniqueId => m_VersionId; + + public PackageSource source => PackageSource.Unknown; + + public IEnumerable errors => m_Errors; + + public IEnumerable samples => Enumerable.Empty(); + + public EntitlementsInfo entitlements => null; + + public SemVersion version + { + get { return m_Version; } + set { m_Version = value; } + } + + public DateTime? publishedDate => m_PublishedDate; + + public string publisherId => m_PublisherId; + + public DependencyInfo[] dependencies => null; + + public DependencyInfo[] resolvedDependencies => null; + + public PackageInfo packageInfo => null; + + public bool isInstalled => false; + + public bool isFullyFetched => true; + + public bool isUserVisible => true; + + public bool isAvailableOnDisk => m_IsAvailableOnDisk; + + public bool isVersionLocked => true; + + public bool canBeRemoved => false; + + public bool canBeEmbedded => false; + + public bool isDirectDependency => true; + + public string localPath + { + get { return m_LocalPath; } + set + { + m_LocalPath = value; + m_IsAvailableOnDisk = !string.IsNullOrEmpty(m_LocalPath) && File.Exists(m_LocalPath); + } + } + + public string versionString + { + get { return m_VersionString; } + set { m_VersionString = value; } + } + + public string versionId + { + get { return m_VersionId; } + set { m_VersionId = value; } + } + + public SemVersion supportedVersion => m_SupportedUnityVersion; + + public IEnumerable supportedVersions => m_SupportedUnityVersions; + + public IEnumerable images => m_Images; + + public IEnumerable sizes => m_SizeInfos; + + public IEnumerable links => m_Links; + + public bool HasTag(PackageTag tag) + { + return (m_Tag & tag) == tag; + } + + public AssetStorePackageVersion(AssetStorePackageVersion other, SpecificVersionInfo localInfo = null) + { + m_PackageUniqueId = other.m_PackageUniqueId; + m_DisplayName = other.m_DisplayName; + m_Type = other.m_Type; + m_Author = other.m_Author; + m_Description = other.m_Description; + m_Category = other.m_Category; + m_Errors = other.m_Errors; + m_Version = other.m_Version; + m_PublishedDate = other.m_PublishedDate; + m_PublisherId = other.m_PublisherId; + m_IsAvailableOnDisk = other.m_IsAvailableOnDisk; + m_LocalPath = other.m_LocalPath; + m_VersionString = other.m_VersionString; + m_VersionId = other.m_VersionId; + m_SupportedUnityVersions = other.m_SupportedUnityVersions; + m_SupportedUnityVersion = other.m_SupportedUnityVersion; + m_Images = other.m_Images; + m_SizeInfos = other.m_SizeInfos; + m_Links = other.m_Links; + m_Tag = other.m_Tag; + + if (localInfo != null) + { + m_VersionString = localInfo.versionString; + m_VersionId = localInfo.versionId; + + SemVersion semVer; + if (!SemVersion.TryParse(m_VersionString.Trim(), out semVer)) + { + semVer = new SemVersion(0); + } + m_Version = semVer; + + m_PublishedDate = DateTime.Parse(localInfo.publishedDate); + + var simpleVersion = Regex.Replace(localInfo.supportedVersion, @"(?\d+)\.(?\d+).(?\d+)[abfp].+", "${major}.${minor}.${patch}"); + SemVersion.TryParse(simpleVersion.Trim(), out m_SupportedUnityVersion); + } + } + + public AssetStorePackageVersion(string productId, IDictionary productDetail, SpecificVersionInfo localInfo = null) + { + if (productDetail == null) + { + throw new ArgumentNullException(nameof(productDetail)); + } + + m_Errors = new List(); + m_Type = "assetstore"; + m_Tag = PackageTag.AssetStore; + m_PackageUniqueId = productId; + + try + { + var description = productDetail.ContainsKey("description") ? productDetail["description"] as string : string.Empty; + m_Description = CleanUpHtml(description); + + var publisher = new Dictionary(); + if (productDetail.ContainsKey("productPublisher")) + { + publisher = productDetail["productPublisher"] as Dictionary; + if (publisher.ContainsKey("url") && publisher["url"] is string && (string)publisher["url"] == "http://unity3d.com") + m_Author = "Unity Technologies Inc."; + else + m_Author = publisher.ContainsKey("name") ? publisher["name"] as string : L10n.Tr("Unknown publisher"); + + m_PublisherId = publisher.ContainsKey("externalRef") ? publisher["externalRef"] as string : string.Empty; + } + else + { + m_Author = string.Empty; + m_PublisherId = string.Empty; + } + + m_Category = string.Empty; + if (productDetail.ContainsKey("category")) + { + var categoryInfo = productDetail["category"] as IDictionary; + m_Category = categoryInfo["name"] as string; + } + + if (localInfo != null) + { + m_VersionString = localInfo.versionString; + m_VersionId = localInfo.versionId; + + SemVersion semVer; + if (!SemVersion.TryParse(m_VersionString.Trim(), out semVer)) + { + semVer = new SemVersion(0); + } + m_Version = semVer; + + m_PublishedDate = DateTime.Parse(localInfo.publishedDate); + } + else if (productDetail.ContainsKey("version")) + { + var versionInfo = productDetail["version"] as IDictionary; + m_VersionString = versionInfo["name"] as string; + m_VersionId = versionInfo["id"] as string; + SemVersion semVer; + if (!SemVersion.TryParse(m_VersionString.Trim(), out semVer)) + { + semVer = new SemVersion(0); + } + m_Version = semVer; + + if (versionInfo.ContainsKey("publishedDate")) + { + var date = versionInfo["publishedDate"] as string; + m_PublishedDate = DateTime.Parse(date); + } + else + { + m_PublishedDate = new DateTime(); + } + } + else + { + m_VersionString = string.Empty; + m_VersionId = string.Empty; + m_Version = new SemVersion(0); + } + + m_DisplayName = productDetail.ContainsKey("displayName") ? productDetail["displayName"] as string : $"Package {m_PackageUniqueId}@{m_VersionId}"; + + m_SupportedUnityVersions = new List(); + if (productDetail.ContainsKey("supportedUnityVersions")) + { + var supportedVersions = productDetail["supportedUnityVersions"] as IList; + foreach (var supportedVersion in supportedVersions.Where(v => v is string)) + { + SemVersion version; + if (SemVersion.TryParse(supportedVersion as string, out version)) + m_SupportedUnityVersions.Add(version); + } + + m_SupportedUnityVersions.Sort((left, right) => left.CompareByPrecedence(right)); + } + + if (localInfo != null) + { + var simpleVersion = Regex.Replace(localInfo.supportedVersion, @"(?\d+)\.(?\d+).(?\d+)[abfp].+", "${major}.${minor}.${patch}"); + SemVersion.TryParse(simpleVersion.Trim(), out m_SupportedUnityVersion); + } + else + { + m_SupportedUnityVersion = m_SupportedUnityVersions.LastOrDefault(); + } + + m_Images = new List(); + if (productDetail.ContainsKey("mainImage")) + { + var mainImage = productDetail["mainImage"] as IDictionary; + var thumbnailUrl = mainImage["url"] as string; + thumbnailUrl = thumbnailUrl.Replace("//d2ujflorbtfzji.cloudfront.net/", "//assetstorev1-prd-cdn.unity3d.com/"); + m_Images.Add(new PackageImage + { + type = PackageImage.ImageType.Main, + thumbnailUrl = "http:" + thumbnailUrl, + url = string.Empty + }); + } + + if (productDetail.ContainsKey("images")) + { + var images = productDetail["images"] as IList; + foreach (var image in images) + { + var imageInfo = image as IDictionary; + var type = imageInfo["type"] as string; + if (string.IsNullOrEmpty(type)) + continue; + + var imageType = PackageImage.ImageType.Screenshot; + var thumbnailUrl = imageInfo["thumbnailUrl"] as string; + thumbnailUrl = thumbnailUrl.Replace("//d2ujflorbtfzji.cloudfront.net/", "//assetstorev1-prd-cdn.unity3d.com/"); + + if (type == "sketchfab") + imageType = PackageImage.ImageType.Sketchfab; + else if (type == "youtube") + imageType = PackageImage.ImageType.Youtube; + + var imageUrl = imageInfo["imageUrl"] as string; + if (imageType == PackageImage.ImageType.Screenshot) + imageUrl = "http:" + imageUrl; + + m_Images.Add(new PackageImage + { + type = imageType, + thumbnailUrl = "http:" + thumbnailUrl, + url = imageUrl + }); + } + } + + m_SizeInfos = new List(); + if (productDetail.ContainsKey("uploads")) + { + var uploads = productDetail["uploads"] as IDictionary; + foreach (var key in uploads.Keys) + { + var simpleVersion = Regex.Replace(key, @"(?\d+)\.(?\d+).(?\d+)[abfp].+", "${major}.${minor}.${patch}"); + SemVersion version; + if (SemVersion.TryParse(simpleVersion.Trim(), out version)) + { + var info = uploads[key] as IDictionary; + var assetCount = info["assetCount"] as string; + var downloadSize = info["downloadSize"] as string; + + m_SizeInfos.Add(new PackageSizeInfo + { + supportedUnityVersion = version, + assetCount = string.IsNullOrEmpty(assetCount) ? 0 : ulong.Parse(assetCount), + downloadSize = string.IsNullOrEmpty(downloadSize) ? 0 : ulong.Parse(downloadSize) + }); + } + } + + m_SizeInfos.Sort((left, right) => left.supportedUnityVersion.CompareByPrecedence(right.supportedUnityVersion)); + } + + m_Links = new List(); + + var slug = productDetail.ContainsKey("slug") ? productDetail["slug"] as string : m_PackageUniqueId; + m_Links.Add(new PackageLink {name = "View in the Asset Store", url = $"/packages/p/{slug}"}); + + if (publisher.ContainsKey("url")) + { + var url = publisher["url"] as string; + if (!string.IsNullOrEmpty(url) && Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute)) + m_Links.Add(new PackageLink {name = "Publisher Web Site", url = url}); + } + + if (publisher.ContainsKey("supportUrl")) + { + var url = publisher["supportUrl"] as string; + if (!string.IsNullOrEmpty(url) && Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute)) + m_Links.Add(new PackageLink {name = "Publisher Support", url = url}); + } + + if (productDetail.ContainsKey("state")) + { + var state = productDetail["state"] as string; + if (state.Equals("published", StringComparison.InvariantCultureIgnoreCase)) + m_Tag |= PackageTag.Published; + else if (state.Equals("deprecated", StringComparison.InvariantCultureIgnoreCase)) + m_Tag |= PackageTag.Deprecated; + } + + m_LocalPath = productDetail.ContainsKey("localPath") ? productDetail["localPath"] as string : string.Empty; + m_IsAvailableOnDisk = !string.IsNullOrEmpty(m_LocalPath) && File.Exists(m_LocalPath); + } + catch (Exception e) + { + m_Errors.Add(new Error(NativeErrorCode.Unknown, e.Message)); + } + } + + private static string CleanUpHtml(string source) + { + if (string.IsNullOrEmpty(source)) + return source; + + source = source.Replace("
", "\n"); + + var array = new char[source.Length]; + var arrayIndex = 0; + var inside = false; + + foreach (var c in source.ToCharArray()) + { + if (c == '<') + inside = true; + else if (c == '>') + inside = false; + else + { + if (!inside) + array[arrayIndex++] = c; + } + } + + var text = new string(array, 0, arrayIndex); + text = Regex.Replace(text, @"&#x?\d+;", ""); + text = text.Replace(" ", " "); + text = text.Replace("<", "<"); + text = text.Replace(">", ">"); + text = text.Replace("&", "&"); + text = text.Replace(""", "\""); + text = text.Replace("'", "'"); + text = Regex.Replace(text, @"[\n\r]+", "\n"); + text = text.Trim(' ', '\r', '\n', '\t'); + + return text; + } + } +} diff --git a/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreRestAPI.cs b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreRestAPI.cs new file mode 100644 index 0000000000..c06a5b252a --- /dev/null +++ b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreRestAPI.cs @@ -0,0 +1,314 @@ +// 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 UnityEditor.Connect; + +namespace UnityEditor.PackageManager.UI.AssetStore +{ + internal sealed class AssetStoreRestAPI + { + static IAssetStoreRestAPI s_Instance = null; + public static IAssetStoreRestAPI instance => s_Instance ?? AssetStoreRestAPIInternal.instance; + + internal class AssetStoreRestAPIInternal : IAssetStoreRestAPI + { + private static AssetStoreRestAPIInternal s_Instance; + public static AssetStoreRestAPIInternal instance => s_Instance ?? (s_Instance = new AssetStoreRestAPIInternal()); + + private string m_Host = ""; + private const int kDefaultLimit = 100; + private const string kListUri = "/-/api/purchases"; + private const string kDetailUri = "/-/api/product"; + private const string kUpdateUri = "/-/api/legacy-package-update-info"; + private const string kDownloadUri = "/-/api/legacy-package-download-info"; + + private IASyncHTTPClientFactory m_AsyncHTTPClient; + + private AssetStoreRestAPIInternal() + { + m_AsyncHTTPClient = new ASyncHTTPClientFactory(); + m_Host = UnityConnect.instance.GetConfigurationURL(CloudConfigUrl.CloudPackagesApi); + } + + public void GetProductIDList(int startIndex, int limit, string searchText, Action doneCallbackAction) + { + var returnList = new ProductList + { + total = 0, + startIndex = startIndex, + isValid = false, + searchText = searchText, + list = new List() + }; + + AssetStoreOAuth.instance.FetchUserInfo(userInfo => + { + if (!userInfo.isValid) + { + returnList.errorMessage = userInfo.errorMessage; + doneCallbackAction?.Invoke(returnList); + return; + } + + limit = limit > 0 ? limit : kDefaultLimit; + searchText = string.IsNullOrEmpty(searchText) ? "" : searchText; + var httpRequest = m_AsyncHTTPClient.GetASyncHTTPClient($"{m_Host}{kListUri}?offset={startIndex}&limit={limit}&query={System.Uri.EscapeDataString(searchText)}"); + httpRequest.header["Authorization"] = "Bearer " + userInfo.accessToken.access_token; + httpRequest.doneCallback = httpClient => + { + var errorMessage = "Failed to parse JSON."; + if (httpClient.IsSuccess() && httpClient.responseCode == 200) + { + try + { + var res = Json.Deserialize(httpClient.text) as Dictionary; + if (res != null) + { + var total = (long)res["total"]; + returnList.total = total; + returnList.isValid = true; + + if (total == 0) + { + doneCallbackAction?.Invoke(returnList); + return; + } + + var results = res["results"] as IList; + foreach (var result in results) + { + var item = result as Dictionary; + var packageId = item["packageId"]; + returnList.list.Add((long)packageId); + } + + doneCallbackAction?.Invoke(returnList); + return; + } + } + catch (Exception e) + { + errorMessage = e.Message; + } + } + else + { + errorMessage = httpClient.text; + } + + returnList.errorMessage = errorMessage; + doneCallbackAction?.Invoke(returnList); + }; + httpRequest.Begin(); + }); + } + + public void GetProductDetail(long productID, Action> doneCallbackAction) + { + AssetStoreOAuth.instance.FetchUserInfo(userInfo => + { + if (!userInfo.isValid) + { + var ret = new Dictionary(); + ret["errorMessage"] = userInfo.errorMessage; + doneCallbackAction?.Invoke(ret); + return; + } + + var httpRequest = m_AsyncHTTPClient.GetASyncHTTPClient($"{m_Host}{kDetailUri}/{productID}"); + httpRequest.header["Authorization"] = "Bearer " + userInfo.accessToken.access_token; + + var etag = AssetStoreCache.instance.GetLastETag(productID); + httpRequest.header["If-None-Match"] = etag.Replace("\"", "\\\""); + + httpRequest.doneCallback = httpClient => + { + var ret = new Dictionary(); + var errorMessage = "Failed to parse JSON."; + if (httpClient.IsSuccess() && httpClient.responseCode == 200) + { + try + { + if (httpClient.responseHeader.ContainsKey("ETag")) + { + etag = httpClient.responseHeader["ETag"]; + } + + ret = Json.Deserialize(httpClient.text) as Dictionary; + if (ret != null) + { + AssetStoreCache.instance.SetLastETag(productID, etag); + doneCallbackAction?.Invoke(ret); + return; + } + } + catch (Exception e) + { + errorMessage = e.Message; + } + } + else + { + errorMessage = httpClient.text; + } + + ret = new Dictionary {["errorMessage"] = errorMessage}; + doneCallbackAction?.Invoke(ret); + }; + httpRequest.Begin(); + }); + } + + public void GetDownloadDetail(long productID, Action doneCallbackAction) + { + var downloadInfo = new DownloadInformation + { + isValid = false + }; + + AssetStoreOAuth.instance.FetchUserInfo(userInfo => + { + if (!userInfo.isValid) + { + downloadInfo.errorMessage = userInfo.errorMessage; + doneCallbackAction?.Invoke(downloadInfo); + return; + } + + var httpRequest = m_AsyncHTTPClient.GetASyncHTTPClient($"{m_Host}{kDownloadUri}/{productID}"); + httpRequest.header["Content-Type"] = "application/json"; + httpRequest.header["Authorization"] = "Bearer " + userInfo.accessToken.access_token; + httpRequest.doneCallback = httpClient => + { + var errorMessage = "Failed to parse JSON."; + if (httpClient.IsSuccess() && httpClient.responseCode == 200) + { + try + { + var res = Json.Deserialize(httpClient.text) as Dictionary; + if (res != null) + { + var downloadRes = res["result"] as Dictionary; + var download = downloadRes["download"] as Dictionary; + downloadInfo.isValid = true; + downloadInfo.CategoryName = download["filename_safe_category_name"] as string; + downloadInfo.PackageName = download["filename_safe_package_name"] as string; + downloadInfo.PublisherName = download["filename_safe_publisher_name"] as string; + downloadInfo.PackageId = download["id"] as string; + downloadInfo.Key = download["key"] as string; + downloadInfo.Url = download["url"] as string; + doneCallbackAction?.Invoke(downloadInfo); + return; + } + } + catch (Exception e) + { + errorMessage = e.Message; + } + } + else + errorMessage = httpClient.text; + + downloadInfo.errorMessage = errorMessage; + doneCallbackAction?.Invoke(downloadInfo); + }; + httpRequest.Begin(); + }); + } + + public void GetProductUpdateDetail(List localPackages, Action> doneCallbackAction) + { + AssetStoreOAuth.instance.FetchUserInfo(userInfo => + { + if (!userInfo.isValid) + { + var ret = new Dictionary(); + ret["errorMessage"] = userInfo.errorMessage; + doneCallbackAction?.Invoke(ret); + return; + } + + if (localPackages?.Count == 0) + { + doneCallbackAction?.Invoke(new Dictionary()); + return; + } + + var packageList = new List>(); + + foreach (var product in localPackages) + { + var dictData = new Dictionary(); + + dictData["local_path"] = product.packagePath; + + try + { + var localPackageJson = Json.Deserialize(product.jsonInfo) as Dictionary; + if (localPackageJson == null) + { + var ret = new Dictionary(); + ret["errorMessage"] = "Failed to parse JSON in local package"; + doneCallbackAction?.Invoke(ret); + return; + } + + dictData["id"] = localPackageJson["id"] as string; + dictData["version"] = localPackageJson["version"] as string; + dictData["version_id"] = localPackageJson["version_id"] as string; + } + catch (Exception e) + { + Dictionary ret = new Dictionary(); + ret["errorMessage"] = e.Message; + doneCallbackAction?.Invoke(ret); + return; + } + + packageList.Add(dictData); + } + + var data = Json.Serialize(packageList); + var url = $"{m_Host}{kUpdateUri}"; + + var httpRequest = m_AsyncHTTPClient.GetASyncHTTPClient(url, "POST"); + httpRequest.postData = data; + httpRequest.header["Content-Type"] = "application/json"; + httpRequest.header["Authorization"] = "Bearer " + userInfo.accessToken.access_token; + httpRequest.doneCallback = httpClient => + { + var errorMessage = "Failed to parse JSON."; + if (httpClient.IsSuccess() && httpClient.responseCode == 200) + { + try + { + var res = Json.Deserialize(httpClient.text) as Dictionary; + if (res != null) + { + var result = res["result"] as Dictionary; + doneCallbackAction?.Invoke(result); + return; + } + } + catch (Exception e) + { + errorMessage = e.Message; + } + } + else + { + errorMessage = httpClient.text; + } + + var ret = new Dictionary {["errorMessage"] = errorMessage}; + doneCallbackAction?.Invoke(ret); + }; + httpRequest.Begin(); + }); + } + } + } +} diff --git a/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreUtils.cs b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreUtils.cs new file mode 100644 index 0000000000..4b31fa24d7 --- /dev/null +++ b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreUtils.cs @@ -0,0 +1,61 @@ +// 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 UnityEditor.Connect; +using UnityEngine; +using UnityAssetStoreUtils = UnityEditor.AssetStoreUtils; +using UnityAssetStorePackageInfo = UnityEditor.PackageInfo; + +namespace UnityEditor.PackageManager.UI +{ + internal sealed class AssetStoreUtils + { + static IAssetStoreUtils s_Instance = null; + public static IAssetStoreUtils instance => s_Instance ?? AssetStoreUtilsInternal.instance; + + private class AssetStoreUtilsInternal : IAssetStoreUtils + { + private static AssetStoreUtilsInternal s_Instance; + public static AssetStoreUtilsInternal instance => s_Instance ?? (s_Instance = new AssetStoreUtilsInternal()); + + private AssetStoreUtilsInternal() + { + } + + public void Download(string id, string url, string[] destination, string key, string jsonData, bool resumeOK) + { + UnityAssetStoreUtils.Download(id, url, destination, key, jsonData, resumeOK); + } + + public string CheckDownload(string id, string url, string[] destination, string key) + { + return UnityAssetStoreUtils.CheckDownload(id, url, destination, key); + } + + public bool AbortDownload(string id, string[] destination) + { + return UnityAssetStoreUtils.AbortDownload(id, destination); + } + + public void RegisterDownloadDelegate(ScriptableObject d) + { + UnityAssetStoreUtils.RegisterDownloadDelegate(d); + } + + public void UnRegisterDownloadDelegate(ScriptableObject d) + { + UnityAssetStoreUtils.UnRegisterDownloadDelegate(d); + } + + public List GetLocalPackageList() + { + return UnityEditor.PackageInfo.GetPackageList().ToList(); + } + + public string assetStoreUrl => UnityConnect.instance.GetConfigurationURL(CloudConfigUrl.CloudAssetStoreUrl); + } + } +} diff --git a/Modules/PackageManagerUI/Editor/Services/Common/ApplicationUtil.cs b/Modules/PackageManagerUI/Editor/Services/Common/ApplicationUtil.cs index 6ce93e1873..96c81bd0f4 100644 --- a/Modules/PackageManagerUI/Editor/Services/Common/ApplicationUtil.cs +++ b/Modules/PackageManagerUI/Editor/Services/Common/ApplicationUtil.cs @@ -4,6 +4,8 @@ using System; using System.Linq; +using UnityEditor.Connect; +using UnityEditorInternal; using UnityEngine; namespace UnityEditor.PackageManager.UI @@ -14,16 +16,66 @@ internal sealed class ApplicationUtil public static readonly string k_ResetPackagesMenuPath = "Help/" + k_ResetPackagesMenuName; static IApplicationUtil s_Instance = null; - public static IApplicationUtil instance { get { return s_Instance ?? ApplicationUtilInternal.instance; } } + public static IApplicationUtil instance => s_Instance ?? ApplicationUtilInternal.instance; private class ApplicationUtilInternal : IApplicationUtil { - static ApplicationUtilInternal s_Instance = null; - public static ApplicationUtilInternal instance { get { return s_Instance ?? (s_Instance = new ApplicationUtilInternal()); } } + private static ApplicationUtilInternal s_Instance; + public static ApplicationUtilInternal instance => s_Instance ?? (s_Instance = new ApplicationUtilInternal()); public event Action onFinishCompiling = delegate {}; private bool m_CheckingCompilation = false; + public event Action onUserLoginStateChange = delegate {}; + public event Action onInternetReachabilityChange = delegate {}; + + private ConnectInfo m_ConnectInfo; + + private bool m_IsInternetReachable; + private double m_LastInternetCheck; + + public string userAppDataPath => InternalEditorUtility.userAppDataFolder; + + private ApplicationUtilInternal() + { + m_ConnectInfo = UnityConnect.instance.connectInfo; + UnityConnect.instance.StateChanged += OnStateChanged; + + m_IsInternetReachable = Application.internetReachability == NetworkReachability.ReachableViaLocalAreaNetwork; + m_LastInternetCheck = EditorApplication.timeSinceStartup; + EditorApplication.update += CheckInternetReachability; + } + + private void CheckInternetReachability() + { + if (EditorApplication.timeSinceStartup - m_LastInternetCheck < 2.0) + return; + + m_LastInternetCheck = EditorApplication.timeSinceStartup; + var isInternetReachable = Application.internetReachability == NetworkReachability.ReachableViaLocalAreaNetwork; + if (isInternetReachable != m_IsInternetReachable) + { + m_IsInternetReachable = isInternetReachable; + onInternetReachabilityChange?.Invoke(m_IsInternetReachable); + } + } + + private void OnStateChanged(ConnectInfo state) + { + var loginChanged = (m_ConnectInfo.ready && m_ConnectInfo.loggedIn && !state.loggedIn) || + (m_ConnectInfo.ready && !m_ConnectInfo.loggedIn && state.loggedIn); + + var onlineChanged = (m_ConnectInfo.ready && m_ConnectInfo.online && !state.online) || + (m_ConnectInfo.ready && !m_ConnectInfo.online && state.online); + + m_ConnectInfo = state; + + if (loginChanged) + onUserLoginStateChange?.Invoke(m_ConnectInfo.loggedIn); + if (onlineChanged) + onInternetReachabilityChange?.Invoke(m_ConnectInfo.online); + } + public bool isPreReleaseVersion { get @@ -44,7 +96,22 @@ public string shortUnityVersion public bool isInternetReachable { - get { return Application.internetReachability != NetworkReachability.NotReachable; } + get { return m_IsInternetReachable; } + } + + public bool isUserLoggedIn + { + get { return m_ConnectInfo.ready && m_ConnectInfo.loggedIn; } + } + + public void ShowLogin() + { + UnityConnect.instance.ShowLogin(); + } + + public void OpenURL(string url) + { + Application.OpenURL(url); } public bool isCompiling diff --git a/Modules/PackageManagerUI/Editor/Services/Common/DownloadProgress.cs b/Modules/PackageManagerUI/Editor/Services/Common/DownloadProgress.cs new file mode 100644 index 0000000000..52a2e37fc4 --- /dev/null +++ b/Modules/PackageManagerUI/Editor/Services/Common/DownloadProgress.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 UnityEngine; + +namespace UnityEditor.PackageManager.UI +{ + [Serializable] + internal class DownloadProgress + { + public enum State + { + Started, + InProgress, + Completed, + Decrypting, + Aborted, + Error + } + + public string packageId; + public State state; + public ulong current; + public ulong total; + public string message; + + public DownloadProgress(string packageId) + { + this.packageId = packageId; + state = State.Started; + current = 0; + total = 0; + message = string.Empty; + } + } +} diff --git a/Modules/PackageManagerUI/Editor/Services/Common/PlaceholderPackage.cs b/Modules/PackageManagerUI/Editor/Services/Common/PlaceholderPackage.cs new file mode 100644 index 0000000000..b6457318d6 --- /dev/null +++ b/Modules/PackageManagerUI/Editor/Services/Common/PlaceholderPackage.cs @@ -0,0 +1,62 @@ +// 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 UnityEngine; + +namespace UnityEditor.PackageManager.UI +{ + [Serializable] + internal class PlaceholderPackage : IPackage + { + [SerializeField] + private string m_UniqueId; + + public string name => string.Empty; + public string uniqueId => m_UniqueId; + + public string displayName => m_Version.displayName; + + [SerializeField] + private PlaceholderPackageVersion m_Version; + + public IEnumerable versions => new[] { m_Version }; + public IEnumerable keyVersions => new[] { m_Version }; + public IPackageVersion installedVersion => null; + public IPackageVersion latestVersion => m_Version; + public IPackageVersion latestPatch => m_Version; + public IPackageVersion recommendedVersion => m_Version; + public IPackageVersion primaryVersion => m_Version; + + [SerializeField] + private PackageState m_State; + public PackageState state => m_State; + + public bool isDiscoverable => true; + + public IEnumerable errors => Enumerable.Empty(); + + public void AddError(Error error) + { + } + + public void ClearErrors() + { + } + + public PlaceholderPackage(string uniqueId, PackageTag tag = PackageTag.None, PackageSource source = PackageSource.Unknown, PackageState state = PackageState.InProgress) + { + m_UniqueId = uniqueId; + m_State = state; + m_Version = new PlaceholderPackageVersion(uniqueId, uniqueId, tag, source); + } + + public IPackage Clone() + { + return (IPackage)MemberwiseClone(); + } + } +} diff --git a/Modules/PackageManagerUI/Editor/Services/Common/PlaceholderPackageVersion.cs b/Modules/PackageManagerUI/Editor/Services/Common/PlaceholderPackageVersion.cs new file mode 100644 index 0000000000..e7f41f62cc --- /dev/null +++ b/Modules/PackageManagerUI/Editor/Services/Common/PlaceholderPackageVersion.cs @@ -0,0 +1,103 @@ +// 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 UnityEngine; + +namespace UnityEditor.PackageManager.UI +{ + [Serializable] + internal class PlaceholderPackageVersion : IPackageVersion + { + [SerializeField] + private string m_PackageUniqueId; + public string packageUniqueId => m_PackageUniqueId; + + [SerializeField] + private string m_UniqueId; + public string uniqueId => m_UniqueId; + public string name => string.Empty; + + [SerializeField] + private PackageSource m_Source; + public PackageSource source => m_Source; + + public string displayName => string.Empty; + + public string type => string.Empty; + + public string author => string.Empty; + + public string description => string.Empty; + + public string category => string.Empty; + + public IEnumerable errors => Enumerable.Empty(); + + public IEnumerable samples => Enumerable.Empty(); + + public SemVersion version => new SemVersion(0); + + public EntitlementsInfo entitlements => null; + + public DateTime? publishedDate => null; + + public string publisherId => null; + + public DependencyInfo[] dependencies => null; + + public DependencyInfo[] resolvedDependencies => null; + + public PackageInfo packageInfo => null; + + public bool isInstalled => false; + + public bool isFullyFetched => true; + + public bool isUserVisible => true; + + public bool isAvailableOnDisk => false; + + public bool isVersionLocked => true; + + public bool canBeRemoved => false; + + public bool canBeEmbedded => false; + + public bool isDirectDependency => true; + + public string localPath => string.Empty; + + public string versionString => string.Empty; + + public string versionId => string.Empty; + + public IEnumerable supportedVersions => Enumerable.Empty(); + + public IEnumerable images => Enumerable.Empty(); + + public IEnumerable sizes => Enumerable.Empty(); + + public IEnumerable links => Enumerable.Empty(); + + public SemVersion supportedVersion => null; + + [SerializeField] + private PackageTag m_Tag; + public bool HasTag(PackageTag tag) + { + return (m_Tag & tag) != 0; + } + + public PlaceholderPackageVersion(string packageUniqueId, string uniqueId, PackageTag tag = PackageTag.None, PackageSource source = PackageSource.Unknown) + { + m_PackageUniqueId = packageUniqueId; + m_UniqueId = uniqueId; + m_Tag = tag; + m_Source = source; + } + } +} diff --git a/Modules/PackageManagerUI/Editor/Services/Common/PlayModeDownload.cs b/Modules/PackageManagerUI/Editor/Services/Common/PlayModeDownload.cs new file mode 100644 index 0000000000..b8990e73dc --- /dev/null +++ b/Modules/PackageManagerUI/Editor/Services/Common/PlayModeDownload.cs @@ -0,0 +1,73 @@ +// 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; + +namespace UnityEditor.PackageManager.UI +{ + [Serializable] + internal class PlayModeDownloadState : ScriptableSingleton + { + [SerializeField] + public bool skipShowDialog; + } + + [InitializeOnLoad] + internal static class PlayModeDownload + { + static PlayModeDownload() + { + if (!PlayModeDownloadState.instance.skipShowDialog) + EditorApplication.playModeStateChanged += PlayModeStateChanged; + } + + private static void PlayModeStateChanged(PlayModeStateChange state) + { + if (PlayModeDownloadState.instance.skipShowDialog) + return; + + if (state == PlayModeStateChange.ExitingEditMode) + { + if (AssetStore.AssetStoreClient.instance.IsAnyDownloadInProgress()) + { + var accept = EditorUtility.DisplayDialog(L10n.Tr("Package download in progress"), + L10n.Tr("Please note that entering Play Mode while Unity is downloading a package may impact performance"), + L10n.Tr("Got it"), L10n.Tr("Cancel")); + + if (accept) + { + SetSkipDialog(); + } + else + { + EditorApplication.isPlaying = false; + } + } + } + } + + private static void SetSkipDialog() + { + PlayModeDownloadState.instance.skipShowDialog = true; + // Checking for this event is no longer needed + EditorApplication.playModeStateChanged -= PlayModeStateChanged; + } + + public static bool CanBeginDownload() + { + if (!EditorApplication.isPlaying || PlayModeDownloadState.instance.skipShowDialog) + return true; + + var accept = EditorUtility.DisplayDialog(L10n.Tr("Play Mode in progress"), + L10n.Tr("Please note that making changes in the Package Manager while in Play Mode may impact performance."), + L10n.Tr("Got it"), L10n.Tr("Cancel")); + + if (accept) + SetSkipDialog(); + + return accept; + } + } +} diff --git a/Modules/PackageManagerUI/Editor/Services/Common/VisualElementExtensions.cs b/Modules/PackageManagerUI/Editor/Services/Common/VisualElementExtensions.cs index b197057860..d1cf0541c0 100644 --- a/Modules/PackageManagerUI/Editor/Services/Common/VisualElementExtensions.cs +++ b/Modules/PackageManagerUI/Editor/Services/Common/VisualElementExtensions.cs @@ -2,12 +2,22 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License +using System; using UnityEngine.UIElements; namespace UnityEditor.PackageManager.UI { internal static class VisualElementExtensions { + public static void OnLeftClick(this VisualElement element, Action action) + { + element.RegisterCallback(e => + { + if (e.button == 0) + action?.Invoke(); + }); + } + public static void EnableClass(this VisualElement element, string classname, bool enable) { element.RemoveFromClassList(classname); diff --git a/Modules/PackageManagerUI/Editor/Services/Interfaces/IApplicationUtil.cs b/Modules/PackageManagerUI/Editor/Services/Interfaces/IApplicationUtil.cs index 9c4b97f91f..171f8c3f90 100644 --- a/Modules/PackageManagerUI/Editor/Services/Interfaces/IApplicationUtil.cs +++ b/Modules/PackageManagerUI/Editor/Services/Interfaces/IApplicationUtil.cs @@ -8,6 +8,12 @@ namespace UnityEditor.PackageManager.UI { internal interface IApplicationUtil { + event Action onUserLoginStateChange; + + event Action onInternetReachabilityChange; + + event Action onFinishCompiling; + bool isPreReleaseVersion { get; } string shortUnityVersion { get; } @@ -16,6 +22,12 @@ internal interface IApplicationUtil bool isCompiling { get; } - event Action onFinishCompiling; + bool isUserLoggedIn { get; } + + string userAppDataPath { get; } + + void ShowLogin(); + + void OpenURL(string url); } } diff --git a/Modules/PackageManagerUI/Editor/Services/Interfaces/IAssetStoreCache.cs b/Modules/PackageManagerUI/Editor/Services/Interfaces/IAssetStoreCache.cs new file mode 100644 index 0000000000..6fd3a2687e --- /dev/null +++ b/Modules/PackageManagerUI/Editor/Services/Interfaces/IAssetStoreCache.cs @@ -0,0 +1,19 @@ +// 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.PackageManager.UI +{ + internal interface IAssetStoreCache + { + string GetLastETag(long productId); + + void SetLastETag(long productId, string etag); + + Texture2D LoadImage(long productId, string url); + + void SaveImage(long productId, string url, Texture2D texture); + } +} diff --git a/Modules/PackageManagerUI/Editor/Services/Interfaces/IAssetStoreClient.cs b/Modules/PackageManagerUI/Editor/Services/Interfaces/IAssetStoreClient.cs new file mode 100644 index 0000000000..fbf89a41b0 --- /dev/null +++ b/Modules/PackageManagerUI/Editor/Services/Interfaces/IAssetStoreClient.cs @@ -0,0 +1,59 @@ +// 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 UnityEditor.PackageManager.UI.AssetStore; + +namespace UnityEditor.PackageManager.UI +{ + internal interface IAssetStoreClient + { + event Action onProductListFetched; + + event Action onProductFetched; + + event Action> onPackagesChanged; + + event Action onDownloadProgress; + + event Action onListOperationStart; + event Action onListOperationFinish; + + event Action onFetchDetailsStart; + event Action onFetchDetailsFinish; + + event Action onOperationError; + + void List(int offset, int limit, string searchText = "", bool fetchDetails = true); + + void Fetch(long productId); + + void FetchDetails(IEnumerable packageIds); + + void Refresh(IPackage package); + + void Refresh(IEnumerable packages); + + bool IsAnyDownloadInProgress(); + + bool IsDownloadInProgress(string packageId); + + bool GetDownloadProgress(string packageId, out DownloadProgress progress); + + void AbortDownload(string packageId); + + void AbortAllDownloads(); + + void Download(string packageId); + + void OnDownloadProgress(string packageId, string message, ulong bytes, ulong total); + + void Setup(); + + void Clear(); + + void Reset(); + } +} diff --git a/Modules/PackageManagerUI/Editor/Services/Interfaces/IAssetStoreOAuth.cs b/Modules/PackageManagerUI/Editor/Services/Interfaces/IAssetStoreOAuth.cs new file mode 100644 index 0000000000..0a579548d0 --- /dev/null +++ b/Modules/PackageManagerUI/Editor/Services/Interfaces/IAssetStoreOAuth.cs @@ -0,0 +1,13 @@ +// 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.PackageManager.UI.AssetStore +{ + internal interface IAssetStoreOAuth + { + void FetchUserInfo(Action doneCallbackInfo); + } +} diff --git a/Modules/PackageManagerUI/Editor/Services/Interfaces/IAssetStoreRestAPI.cs b/Modules/PackageManagerUI/Editor/Services/Interfaces/IAssetStoreRestAPI.cs new file mode 100644 index 0000000000..1bf7816ad6 --- /dev/null +++ b/Modules/PackageManagerUI/Editor/Services/Interfaces/IAssetStoreRestAPI.cs @@ -0,0 +1,43 @@ +// 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; + +namespace UnityEditor.PackageManager.UI +{ + internal class DownloadInformation + { + public string CategoryName; + public string PackageName; + public string PublisherName; + public string PackageId; + public string Key; + public string Url; + public bool isValid; + public string errorMessage; + } + + [Serializable] + internal class ProductList + { + public long total; + public int startIndex; + public bool isValid; + public string searchText; + public string errorMessage; + public List list = new List(); + } + + internal interface IAssetStoreRestAPI + { + void GetProductIDList(int startIndex, int limit, string searchText, Action doneCallbackAction); + + void GetProductDetail(long productID, Action> doneCallbackAction); + + void GetDownloadDetail(long productID, Action doneCallbackAction); + + void GetProductUpdateDetail(List localPackages, Action> doneCallbackAction); + } +} diff --git a/Modules/PackageManagerUI/Editor/Services/Interfaces/IAssetStoreUtils.cs b/Modules/PackageManagerUI/Editor/Services/Interfaces/IAssetStoreUtils.cs new file mode 100644 index 0000000000..55a3c859c1 --- /dev/null +++ b/Modules/PackageManagerUI/Editor/Services/Interfaces/IAssetStoreUtils.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.Collections.Generic; +using UnityEngine; + +namespace UnityEditor.PackageManager.UI +{ + internal interface IAssetStoreUtils + { + void Download(string id, string url, string[] destination, string key, string jsonData, bool resumeOK); + + string CheckDownload(string id, string url, string[] destination, string key); + + bool AbortDownload(string id, string[] destination); + + void RegisterDownloadDelegate(ScriptableObject d); + + void UnRegisterDownloadDelegate(ScriptableObject d); + + List GetLocalPackageList(); + + string assetStoreUrl { get; } + } +} diff --git a/Modules/PackageManagerUI/Editor/Services/Interfaces/IAsyncHTTPClientFactory.cs b/Modules/PackageManagerUI/Editor/Services/Interfaces/IAsyncHTTPClientFactory.cs new file mode 100644 index 0000000000..00710bbbd7 --- /dev/null +++ b/Modules/PackageManagerUI/Editor/Services/Interfaces/IAsyncHTTPClientFactory.cs @@ -0,0 +1,13 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +namespace UnityEditor.PackageManager.UI.AssetStore +{ + internal interface IASyncHTTPClientFactory + { + IAsyncHTTPClient GetASyncHTTPClient(string url); + + IAsyncHTTPClient GetASyncHTTPClient(string url, string method); + } +} diff --git a/Modules/PackageManagerUI/Editor/Services/Interfaces/IDownloadOperation.cs b/Modules/PackageManagerUI/Editor/Services/Interfaces/IDownloadOperation.cs new file mode 100644 index 0000000000..ff079a0e33 --- /dev/null +++ b/Modules/PackageManagerUI/Editor/Services/Interfaces/IDownloadOperation.cs @@ -0,0 +1,24 @@ +// 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; + +namespace UnityEditor.PackageManager.UI.AssetStore +{ + internal class DownloadResult + { + public DownloadProgress.State downloadState; + public string errorMessage; + } + + internal interface IDownloadOperation + { + void AbortDownloadPackageAsync(long productID, Action doneCallbackAction = null); + + void DownloadUnityPackageAsync(long productID, Action doneCallbackAction = null); + + void DownloadImageAsync(long productID, string url, Action doneCallbackAction = null); + } +} diff --git a/Modules/PackageManagerUI/Editor/Services/Interfaces/IPackage.cs b/Modules/PackageManagerUI/Editor/Services/Interfaces/IPackage.cs index 6331ec5af2..aa6c026660 100644 --- a/Modules/PackageManagerUI/Editor/Services/Interfaces/IPackage.cs +++ b/Modules/PackageManagerUI/Editor/Services/Interfaces/IPackage.cs @@ -32,6 +32,7 @@ internal interface IPackage IPackageVersion primaryVersion { get; } PackageState state { get; } + bool isDiscoverable { get; } // package level errors (for upm this refers to operation errors that are separate from the package info) @@ -40,5 +41,7 @@ internal interface IPackage void AddError(Error error); void ClearErrors(); + + IPackage Clone(); } } diff --git a/Modules/PackageManagerUI/Editor/Services/Interfaces/IPackageDatabase.cs b/Modules/PackageManagerUI/Editor/Services/Interfaces/IPackageDatabase.cs index eb26f50890..eb8b5769b8 100644 --- a/Modules/PackageManagerUI/Editor/Services/Interfaces/IPackageDatabase.cs +++ b/Modules/PackageManagerUI/Editor/Services/Interfaces/IPackageDatabase.cs @@ -7,22 +7,12 @@ namespace UnityEditor.PackageManager.UI { - [Flags] - internal enum RefreshOptions : short - { - None = 0, - OfflineMode = 1 << 0, - ListInstalled = 1 << 1, - SearchAll = 1 << 2, - } - internal interface IPackageDatabase { event Action onUpdateTimeChange; - // args 1,2, 3 are added, removed and updated packages respectively - event Action, IEnumerable, IEnumerable> onPackagesChanged; - event Action onPackageVersionUpdated; + // args 1,2, 3 are added, removed and preUpdated, and postUpdated packages respectively + event Action, IEnumerable, IEnumerable, IEnumerable> onPackagesChanged; event Action onInstallSuccess; event Action onUninstallSuccess; @@ -31,14 +21,15 @@ internal interface IPackageDatabase event Action onPackageOperationFinish; event Action onRefreshOperationStart; - event Action onRefreshOperationFinish; + event Action onRefreshOperationFinish; event Action onRefreshOperationError; + event Action onDownloadProgress; + void Setup(); void Clear(); - - void Refresh(RefreshOptions options); + void Reset(); bool isEmpty { get; } bool isInstallOrUninstallInProgress { get; } @@ -53,12 +44,24 @@ internal interface IPackageDatabase void Uninstall(IPackage package); - void Embed(IPackage package); + DownloadProgress GetDownloadProgress(IPackageVersion version); + + bool IsDownloadInProgress(IPackageVersion version); + + void Download(IPackage package); + + void AbortDownload(IPackage package); + + void Import(IPackage package); + + void Embed(IPackageVersion package); void RemoveEmbedded(IPackage package); long lastUpdateTimestamp { get; } IEnumerable allPackages { get; } + IEnumerable assetStorePackages { get; } + IEnumerable upmPackages { get; } void AddPackageError(IPackage package, Error error); void ClearPackageErrors(IPackage package); @@ -74,5 +77,7 @@ internal interface IPackageDatabase void GetPackageAndVersion(string packageUniqueId, string versionUniqueId, out IPackage package, out IPackageVersion version); IEnumerable GetDependentVersions(IPackageVersion version); + + IEnumerable packagesInError { get; } } } diff --git a/Modules/PackageManagerUI/Editor/Services/Interfaces/IPackageVersion.cs b/Modules/PackageManagerUI/Editor/Services/Interfaces/IPackageVersion.cs index f4675fe4bb..a401bd1087 100644 --- a/Modules/PackageManagerUI/Editor/Services/Interfaces/IPackageVersion.cs +++ b/Modules/PackageManagerUI/Editor/Services/Interfaces/IPackageVersion.cs @@ -10,15 +10,19 @@ namespace UnityEditor.PackageManager.UI internal interface IPackageVersion { string name { get; } + string displayName { get; } string type { get; } + string author { get; } string description { get; } + string category { get; } string packageUniqueId { get; } + string uniqueId { get; } // TODO: Might need to create a wrapper `PackageSource` to account for AssetStore package info. @@ -30,7 +34,9 @@ internal interface IPackageVersion SemVersion version { get; } - DateTime? datePublished { get; } + DateTime? publishedDate { get; } + + string publisherId { get; } DependencyInfo[] dependencies { get; } @@ -56,5 +62,23 @@ internal interface IPackageVersion bool canBeEmbedded { get; } bool isDirectDependency { get; } + + string localPath { get; } + + string versionString { get; } + + string versionId { get; } + + SemVersion supportedVersion { get; } + + IEnumerable supportedVersions { get; } + + IEnumerable images { get; } + + IEnumerable sizes { get; } + + IEnumerable links { get; } + + EntitlementsInfo entitlements { get; } } } diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/PackageAssetPostprocessor.cs b/Modules/PackageManagerUI/Editor/Services/Packages/PackageAssetPostprocessor.cs index 72c2709508..730b927045 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/PackageAssetPostprocessor.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/PackageAssetPostprocessor.cs @@ -2,9 +2,7 @@ // 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; namespace UnityEditor.PackageManager.UI { @@ -12,6 +10,10 @@ internal class PackageAssetPostprocessor : AssetPostprocessor { static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) { + var windows = UnityEngine.Resources.FindObjectsOfTypeAll(); + if (windows == null || windows.Length == 0) + return; + var allUpdatedAssets = importedAssets.Concat(deletedAssets).Concat(movedAssets).Concat(movedFromAssetPaths); var packageJsonsUpdated = false; @@ -28,7 +30,7 @@ static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAsse } if (packageJsonsUpdated) - PackageDatabase.instance.Refresh(RefreshOptions.OfflineMode | RefreshOptions.ListInstalled); + PageManager.instance.Refresh(RefreshOptions.UpmListOffline); } } } diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/PackageCreator.cs b/Modules/PackageManagerUI/Editor/Services/Packages/PackageCreator.cs deleted file mode 100644 index cc171215be..0000000000 --- a/Modules/PackageManagerUI/Editor/Services/Packages/PackageCreator.cs +++ /dev/null @@ -1,175 +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.CodeDom; -using System.CodeDom.Compiler; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using UnityEditor.Connect; -using UnityEditorInternal; -using UnityEngine; - -namespace UnityEditor.PackageManager -{ - internal static class PackageCreator - { - private static readonly string k_DefaultOrganizationName = "Undefined"; - private static readonly string k_DefaultName = "Undefined Package"; - - private static int s_MaxNameLoop = 5000; - internal const int k_MaxPackageNameLength = 210; // Max package name length[214] - nDigits(k_MaxNameLoop)[4] - - private static HashSet m_NameSpaces; - - public static string CreatePackage(string path) - { - var packagesFolder = Folders.GetPackagesPath() + "/"; - if (string.IsNullOrEmpty(path) || !path.StartsWith(packagesFolder, StringComparison.InvariantCulture)) - throw new ArgumentException(nameof(path)); - - var organization = UnityConnect.instance.userInfo.valid ? UnityConnect.instance.userInfo.primaryOrg : string.Empty; - var options = CreatePackageTemplateOptions(path.Substring(packagesFolder.Length), organization); - return PackageTemplate.CreatePackage(options); - } - - internal static PackageTemplateOptions CreatePackageTemplateOptions(string displayName, string organization) - { - if (string.IsNullOrEmpty(displayName)) - displayName = k_DefaultName; - - if (string.IsNullOrEmpty(organization)) - organization = k_DefaultOrganizationName; - - var packageDisplayName = GenerateUniquePackageDisplayName(displayName); - var packageName = GenerateUniqueSanitizedPackageName(organization, packageDisplayName, k_DefaultName); - var rootNamespace = GenerateUniqueSanitizedNamespace(organization, packageDisplayName, k_DefaultName); - - return new PackageTemplateOptions() - { - displayName = packageDisplayName, - name = packageName, - rootNamespace = rootNamespace - }; - } - - internal static string GenerateUniquePackageDisplayName(string displayName) - { - displayName = Regex.Replace(displayName, $@"[{Regex.Escape(EditorUtility.GetInvalidFilenameChars())}]", "_"); - var allPackagesDisplayNames = PackageInfo.GetAll().Where(info => info.type != "module").Select(info => info.displayName); - return FindUnique(displayName, allPackagesDisplayNames, " "); - } - - private static string GenerateUniqueSanitizedPackageName(string organization, string name, string defaultName) - { - var sanitizedOrganization = SanitizeName(organization, k_DefaultOrganizationName, @"[^a-zA-Z\-_\d]", "").ToLower(CultureInfo.InvariantCulture); - var sanitizedName = SanitizeName(name, defaultName, @"[^a-zA-Z\-_\d]", "").ToLower(CultureInfo.InvariantCulture); - - var packageName = "com." + sanitizedOrganization + "." + sanitizedName; - if (packageName.Length > k_MaxPackageNameLength) - packageName = packageName.Substring(0, k_MaxPackageNameLength); - - packageName = packageName.TrimEnd('.'); - var allPackagesNames = PackageInfo.GetAll().Select(info => info.name); - return FindUnique(packageName, allPackagesNames); - } - - private static bool IsValidNamespace(string name) - { - try - { - CodeGenerator.ValidateIdentifiers(new CodeNamespace(name)); - return true; - } - catch (Exception) - { - return false; - } - } - - private static string GenerateUniqueSanitizedNamespace(string organization, string name, string defaultName) - { - var rootNamespacePrefix = TitleName(SanitizeName(organization, k_DefaultOrganizationName, @"[^a-zA-Z\d]", " ")); - var rootNamespaceSuffix = TitleName(SanitizeName(name, defaultName, @"[^a-zA-Z\d]", " ")); - - var rootNamespace = rootNamespacePrefix + "." + rootNamespaceSuffix; - - if (!IsValidNamespace(rootNamespace)) - { - rootNamespace = rootNamespacePrefix + "." + defaultName; - if (!IsValidNamespace(rootNamespace)) - { - rootNamespace = k_DefaultOrganizationName + "." + rootNamespaceSuffix; - if (!IsValidNamespace(rootNamespace)) - { - rootNamespace = k_DefaultOrganizationName + "." + defaultName; - } - } - } - - if (m_NameSpaces == null) - { - var assemblies = AppDomain.CurrentDomain.GetAssemblies(); - m_NameSpaces = new HashSet(); - foreach (var assembly in assemblies) - { - var nameSpaces = assembly.GetTypes().Select(t => t.Namespace); - foreach (var nameSpace in nameSpaces) - { - if (!string.IsNullOrEmpty(nameSpace)) - m_NameSpaces.Add(nameSpace); - } - } - } - - return FindUnique(rootNamespace, m_NameSpaces); - } - - private static string SanitizeName(string name, string defaultName, string pattern, string replacement) - { - var sanitizedName = Regex.Replace(name, pattern, replacement); - sanitizedName = Regex.Replace(sanitizedName, @"^[^a-zA-Z]+", ""); - sanitizedName = Regex.Replace(sanitizedName, @"[^a-zA-Z\d]+$", ""); - return string.IsNullOrEmpty(sanitizedName) ? Regex.Replace(defaultName, pattern, replacement) : sanitizedName; - } - - private static string TitleName(string name) - { - var words = name.Split(' '); - var titleName = new StringBuilder(); - foreach (var word in words) - { - if (!string.IsNullOrEmpty(word)) - titleName.Append(CultureInfo.InvariantCulture.TextInfo.ToTitleCase(word.ToLower())); - } - return titleName.ToString(); - } - - private static string FindUnique(string name, IEnumerable list, string spaces = "") - { - if (!list.Any(str => str == name)) - { - return name; - } - - var uniqueName = Regex.Replace(name, $@"{spaces}\d+$", ""); - var regex = new Regex($@"^{Regex.Escape(uniqueName)}{spaces}(?\d+)$"); - var matches = list.Select(str => regex.Match(str)); - if (!matches.Any(match => match.Success)) - { - return $"{uniqueName}{spaces}1"; - } - - var numbers = matches.Where(match => match.Success).Select(match => int.Parse(match.Groups["count"].Value)).OrderBy(n => n); - var missingNumbers = Enumerable.Range(1, s_MaxNameLoop).Except(numbers); - if (!missingNumbers.Any()) - throw new ArgumentOutOfRangeException(); - - return $"{uniqueName}{spaces}{missingNumbers.FirstOrDefault()}"; - } - } -} diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/PackageDatabase.cs b/Modules/PackageManagerUI/Editor/Services/Packages/PackageDatabase.cs index a1b92d7bd3..63f02ee10d 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/PackageDatabase.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/PackageDatabase.cs @@ -4,7 +4,9 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; +using UnityEditor.PackageManager.UI.AssetStore; using UnityEngine; namespace UnityEditor.PackageManager.UI @@ -17,32 +19,41 @@ internal sealed class PackageDatabase [Serializable] private class PackageDatabaseInternal : ScriptableSingleton, IPackageDatabase, ISerializationCallbackReceiver { - public event Action onUpdateTimeChange = delegate {}; - - public event Action, IEnumerable, IEnumerable> onPackagesChanged = delegate {}; - public event Action onPackageVersionUpdated = delegate {}; - + public event Action onUpdateTimeChange; public event Action onInstallSuccess = delegate {}; public event Action onUninstallSuccess = delegate {}; public event Action onPackageOperationStart = delegate {}; public event Action onPackageOperationFinish = delegate {}; public event Action onRefreshOperationStart = delegate {}; - public event Action onRefreshOperationFinish = delegate {}; + public event Action onRefreshOperationFinish = delegate {}; public event Action onRefreshOperationError = delegate {}; - private readonly Dictionary m_Packages = new Dictionary(); + public event Action onDownloadProgress = delegate {}; + // args 1,2, 3 are added, removed and preUpdated, and postUpdated packages respectively + public event Action, IEnumerable, IEnumerable, IEnumerable> onPackagesChanged = delegate {}; + + private readonly Dictionary m_Packages = new Dictionary(); // a list of unique ids (could be specialUniqueId or packageId) - private List m_SpecialInstallation = new List(); + private List m_SpecialInstallations = new List(); + + // array created to help serialize dictionaries + [SerializeField] + private List m_SerializedUpmPackages = new List(); - // arrays created to help serialize dictionaries - private UpmPackage[] m_SerializedUpmPackages; + [SerializeField] + private List m_SerializedAssetStorePackages = new List(); [NonSerialized] - private List m_RefreshOperationsInProgress; + private List m_RefreshOperationsInProgress = new List(); + + [SerializeField] + private bool m_SetupDone; public bool isEmpty { get { return !m_Packages.Any(); } } + private static readonly IPackage[] k_EmptyList = new IPackage[0] {}; + public bool isInstallOrUninstallInProgress { // add, embed -> install, remove -> uninstall @@ -50,6 +61,8 @@ public bool isInstallOrUninstallInProgress } public IEnumerable allPackages { get { return m_Packages.Values; } } + public IEnumerable assetStorePackages { get { return m_Packages.Values.Where(p => p is AssetStorePackage); } } + public IEnumerable upmPackages { get { return m_Packages.Values.Where(p => p is UpmPackage); } } private long m_LastUpdateTimestamp = 0; public long lastUpdateTimestamp { get { return m_LastUpdateTimestamp; } } @@ -135,9 +148,7 @@ private void GetUpmPackageAndVersion(string name, string versionIdentifier, out public IEnumerable GetDependentVersions(IPackageVersion version) { var installedRoots = allPackages.Select(p => p.installedVersion).Where(p => p?.isDirectDependency ?? false); - var dependsOnPackage = installedRoots.Where(p => - p.resolvedDependencies.Select(r => r.name).Contains(version.name)); - + var dependsOnPackage = installedRoots.Where(p => p.resolvedDependencies?.Any(r => r.name == version.name) ?? false); return dependsOnPackage; } @@ -145,97 +156,211 @@ public void OnAfterDeserialize() { foreach (var p in m_SerializedUpmPackages) m_Packages[p.uniqueId] = p; + + foreach (var p in m_SerializedAssetStorePackages) + m_Packages[p.uniqueId] = p; } public void OnBeforeSerialize() { - m_SerializedUpmPackages = m_Packages.Values.Cast().ToArray(); + m_SerializedUpmPackages = new List(); + m_SerializedAssetStorePackages = new List(); + + foreach (var package in m_Packages.Values) + { + if (package is AssetStorePackage) + m_SerializedAssetStorePackages.Add((AssetStorePackage)package); + else if (package is UpmPackage) + m_SerializedUpmPackages.Add((UpmPackage)package); + } } public void AddPackageError(IPackage package, Error error) { + var packagePreUpdate = package.Clone(); package.AddError(error); - onPackagesChanged(Enumerable.Empty(), Enumerable.Empty(), new IPackage[] { package }); + onPackagesChanged?.Invoke(k_EmptyList, k_EmptyList, new[] { packagePreUpdate }, new[] { package }); } public void ClearPackageErrors(IPackage package) { + var packagePreUpdate = package.Clone(); package.ClearErrors(); - onPackagesChanged(Enumerable.Empty(), Enumerable.Empty(), new IPackage[] { package }); + onPackagesChanged?.Invoke(k_EmptyList, k_EmptyList, new[] { packagePreUpdate }, new[] { package }); } + public IEnumerable packagesInError => allPackages.Where(p => p.errors.Any()); + public void Setup() { - UpmClient.instance.Setup(); + System.Diagnostics.Debug.Assert(!m_SetupDone); + m_SetupDone = true; - UpmClient.instance.onPackagesChanged += OnUpmPackagesChanged; + UpmClient.instance.onPackagesChanged += OnPackagesChanged; UpmClient.instance.onPackageVersionUpdated += OnUpmPackageVersionUpdated; - UpmClient.instance.onListOperation += OnUpmListOrSearchOperation; UpmClient.instance.onSearchAllOperation += OnUpmListOrSearchOperation; UpmClient.instance.onSearchAllOperation += OnUpmSearchAllOperation; - UpmClient.instance.onAddOperation += OnUpmAddOperation; UpmClient.instance.onEmbedOperation += OnUpmEmbedOperation; UpmClient.instance.onRemoveOperation += OnUpmRemoveOperation; + UpmClient.instance.Setup(); + + AssetStore.AssetStoreClient.instance.onPackagesChanged += OnPackagesChanged; + AssetStore.AssetStoreClient.instance.onDownloadProgress += OnDownloadProgress; + AssetStore.AssetStoreClient.instance.onListOperationStart += OnAssetStoreOperationStart; + AssetStore.AssetStoreClient.instance.onListOperationFinish += OnAssetStoreOperationFinish; + AssetStore.AssetStoreClient.instance.onOperationError += OnAssetStoreOperationError; + AssetStore.AssetStoreClient.instance.Setup(); + + ApplicationUtil.instance.onUserLoginStateChange += OnUserLoginStateChange; + + //if (m_RefreshedOnce) + // Refresh(RefreshOptions.Purchased | RefreshOptions.OfflineMode); } public void Clear() { + System.Diagnostics.Debug.Assert(m_SetupDone); + m_SetupDone = false; + + UpmClient.instance.onPackagesChanged -= OnPackagesChanged; + UpmClient.instance.onPackageVersionUpdated -= OnUpmPackageVersionUpdated; + UpmClient.instance.onListOperation -= OnUpmListOrSearchOperation; + UpmClient.instance.onSearchAllOperation -= OnUpmListOrSearchOperation; + UpmClient.instance.onSearchAllOperation -= OnUpmSearchAllOperation; + UpmClient.instance.onAddOperation -= OnUpmAddOperation; + UpmClient.instance.onEmbedOperation -= OnUpmEmbedOperation; + UpmClient.instance.onRemoveOperation -= OnUpmRemoveOperation; + UpmClient.instance.Clear(); + + AssetStore.AssetStoreClient.instance.onPackagesChanged -= OnPackagesChanged; + AssetStore.AssetStoreClient.instance.onDownloadProgress -= OnDownloadProgress; + AssetStore.AssetStoreClient.instance.onListOperationStart -= OnAssetStoreOperationStart; + AssetStore.AssetStoreClient.instance.onListOperationFinish -= OnAssetStoreOperationFinish; + AssetStore.AssetStoreClient.instance.onOperationError -= OnAssetStoreOperationError; + AssetStore.AssetStoreClient.instance.Clear(); + + ApplicationUtil.instance.onUserLoginStateChange -= OnUserLoginStateChange; + } + + public void Reset() + { + onPackagesChanged?.Invoke(Enumerable.Empty(), m_Packages.Values, Enumerable.Empty(), Enumerable.Empty()); + + Clear(); + + AssetStore.AssetStoreClient.instance.Reset(); + m_Packages.Clear(); - m_SerializedUpmPackages = new UpmPackage[0]; - m_SpecialInstallation.Clear(); + m_SerializedUpmPackages = new List(); + m_SerializedAssetStorePackages = new List(); + m_SpecialInstallations.Clear(); + m_RefreshOperationsInProgress.Clear(); m_LastUpdateTimestamp = 0; - UpmClient.instance.Clear(); + Setup(); } - private void OnUpmPackagesChanged(IEnumerable packages) + private void OnDownloadProgress(DownloadProgress progress) + { + var package = GetPackage(progress.packageId); + if (package != null) + { + var hasError = progress.state == DownloadProgress.State.Error || progress.state == DownloadProgress.State.Aborted; + if (hasError) + package.AddError(new Error(NativeErrorCode.Unknown, progress.message)); + + if (progress.state == DownloadProgress.State.Completed) + { + AssetStore.AssetStoreClient.instance.Refresh(package); + } + + onDownloadProgress?.Invoke(package, progress); + } + } + + private void OnAssetStoreOperationStart() + { + onRefreshOperationStart?.Invoke(); + } + + private void OnAssetStoreOperationFinish() + { + onRefreshOperationFinish?.Invoke(PackageFilterTab.AssetStore); + } + + private void OnAssetStoreOperationError(Error error) + { + onRefreshOperationError?.Invoke(error); + } + + private void OnUserLoginStateChange(bool loggedIn) + { + if (!loggedIn) + { + var assetStorePackages = m_Packages.Where(kp => kp.Value is AssetStorePackage).Select(kp => kp.Value).ToList(); + foreach (var p in assetStorePackages) + m_Packages.Remove(p.uniqueId); + m_SerializedAssetStorePackages = new List(); + + onPackagesChanged?.Invoke(k_EmptyList, assetStorePackages, k_EmptyList, k_EmptyList); + } + } + + private void OnPackagesChanged(IEnumerable packages) { if (!packages.Any()) return; - var addedList = new List(); - var updatedList = new List(); - var removedList = new List(); + var packagesAdded = new List(); + var packagesRemoved = new List(); + + var packagesPreUpdate = new List(); + var packagesPostUpdate = new List(); + + var packagesInstalled = new List(); + foreach (var package in packages) { - var packageName = package.name; + var packageUniqueId = package.uniqueId; var isEmptyPackage = !package.versions.Any(); - var oldPackage = GetPackage(packageName); + var oldPackage = GetPackage(packageUniqueId); if (oldPackage != null && isEmptyPackage) { - removedList.Add(m_Packages[packageName]); - m_Packages.Remove(packageName); + packagesRemoved.Add(m_Packages[packageUniqueId]); + m_Packages.Remove(packageUniqueId); } else if (!isEmptyPackage) { - m_Packages[packageName] = package; + m_Packages[packageUniqueId] = package; if (oldPackage != null) - updatedList.Add(package); + { + packagesPreUpdate.Add(oldPackage); + packagesPostUpdate.Add(package); + } else - addedList.Add(package); + packagesAdded.Add(package); } + + if (m_SpecialInstallations.Any() && package.installedVersion != null && oldPackage?.installedVersion == null) + packagesInstalled.Add(package); } - if (addedList.Any() || updatedList.Any() || removedList.Any()) - onPackagesChanged(addedList, removedList, updatedList); + + if (packagesAdded.Count + packagesRemoved.Count + packagesPostUpdate.Count > 0) + onPackagesChanged?.Invoke(packagesAdded, packagesRemoved, packagesPreUpdate, packagesPostUpdate); // special handling to make sure onInstallSuccess events are called correctly when special unique id is used - if (m_SpecialInstallation.Any()) + for (var i = m_SpecialInstallations.Count - 1; i >= 0; i--) { - var potentialInstalls = addedList.Concat(updatedList).Where(p => p.installedVersion != null); - - for (var i = m_SpecialInstallation.Count - 1; i >= 0; i--) + var match = packagesInstalled.FirstOrDefault(p => p.installedVersion.uniqueId.ToLower().Contains(m_SpecialInstallations[i].ToLower())); + if (match != null) { - var match = potentialInstalls.FirstOrDefault(p => p.installedVersion.uniqueId.ToLower().Contains(m_SpecialInstallation[i].ToLower())); - if (match != null) - { - onInstallSuccess(match, match.installedVersion); - onPackageOperationFinish(match); - m_SpecialInstallation.RemoveAt(i); - } + onInstallSuccess(match, match.installedVersion); + onPackageOperationFinish(match); + m_SpecialInstallations.RemoveAt(i); } } } @@ -246,11 +371,11 @@ private void OnUpmAddOperation(IOperation operation) // as we don't know what package will be installed until the installation finishes (e.g, git packages) if (string.IsNullOrEmpty(operation.packageUniqueId)) { - m_SpecialInstallation.Add(operation.specialUniqueId); + m_SpecialInstallations.Add(operation.specialUniqueId); onPackageOperationStart(null); operation.onOperationError += error => { - m_SpecialInstallation.Remove(operation.specialUniqueId); + m_SpecialInstallations.Remove(operation.specialUniqueId); onPackageOperationFinish(null); }; return; @@ -309,7 +434,7 @@ private void OnUpmSearchAllOperation(IOperation operation) operation.onOperationSuccess += () => { m_LastUpdateTimestamp = operation.timestamp; - onUpdateTimeChange(operation.timestamp); + onUpdateTimeChange?.Invoke(operation.timestamp); }; } @@ -326,9 +451,7 @@ private void OnUpmListOrSearchOperation(IOperation operation) private void OnListOrSearchOperationFinalized(IOperation operation) { m_RefreshOperationsInProgress.Remove(operation); - if (m_RefreshOperationsInProgress.Any()) - return; - onRefreshOperationFinish(); + onRefreshOperationFinish(operation is UpmListOperation ? PackageFilterTab.Local : PackageFilterTab.All); } private void OnUpmPackageVersionUpdated(IPackageVersion version) @@ -336,8 +459,9 @@ private void OnUpmPackageVersionUpdated(IPackageVersion version) var upmPackage = GetPackage(version.packageInfo.name) as UpmPackage; if (upmPackage != null) { + var packagePreUpdate = upmPackage.Clone(); upmPackage.UpdateVersion(version as UpmPackageVersion); - onPackageVersionUpdated(version); + onPackagesChanged?.Invoke(k_EmptyList, k_EmptyList, new[] { packagePreUpdate }, new[] { upmPackage }); } } @@ -365,11 +489,11 @@ public void Uninstall(IPackage package) UpmClient.instance.RemoveByName(package.uniqueId); } - public void Embed(IPackage package) + public void Embed(IPackageVersion packageVersion) { - if (package.installedVersion == null) + if (packageVersion == null || !packageVersion.canBeEmbedded) return; - UpmClient.instance.EmbedByName(package.uniqueId); + UpmClient.instance.EmbedByName(packageVersion.name); } public void RemoveEmbedded(IPackage package) @@ -386,13 +510,47 @@ public void FetchExtraInfo(IPackageVersion version) UpmClient.instance.ExtraFetch(version.uniqueId); } - public void Refresh(RefreshOptions options) + public DownloadProgress GetDownloadProgress(IPackageVersion version) { - var offlineMode = (options & RefreshOptions.OfflineMode) != 0; - if ((options & RefreshOptions.ListInstalled) != 0) - UpmClient.instance.List(offlineMode); - if ((options & RefreshOptions.SearchAll) != 0) - UpmClient.instance.SearchAll(offlineMode); + DownloadProgress progress; + AssetStore.AssetStoreClient.instance.GetDownloadProgress(version.packageUniqueId, out progress); + return progress; + } + + public bool IsDownloadInProgress(IPackageVersion version) + { + return AssetStore.AssetStoreClient.instance.IsDownloadInProgress(version.packageUniqueId); + } + + public void Download(IPackage package) + { + if (!(package is AssetStorePackage)) + return; + + if (!PlayModeDownload.CanBeginDownload()) + return; + + AssetStore.AssetStoreClient.instance.Download(package.uniqueId); + } + + public void AbortDownload(IPackage package) + { + if (!(package is AssetStorePackage)) + return; + + AssetStore.AssetStoreClient.instance.AbortDownload(package.uniqueId); + } + + public void Import(IPackage package) + { + if (!(package is AssetStorePackage)) + return; + + var path = package.primaryVersion.localPath; + if (File.Exists(path)) + { + AssetDatabase.ImportPackage(path, true); + } } } } diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/PackageFilterTab.cs b/Modules/PackageManagerUI/Editor/Services/Packages/PackageFilterTab.cs index c1476498bb..b6d7dbe783 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/PackageFilterTab.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/PackageFilterTab.cs @@ -9,6 +9,7 @@ internal enum PackageFilterTab All = 0, Local, Modules, + AssetStore, InDevelopment } } diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/PackageFiltering.cs b/Modules/PackageManagerUI/Editor/Services/Packages/PackageFiltering.cs index 82fc9d8e6d..e0449c1939 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/PackageFiltering.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/PackageFiltering.cs @@ -13,9 +13,86 @@ internal sealed class PackageFiltering static IPackageFiltering s_Instance = null; public static IPackageFiltering instance { get { return s_Instance ?? PackageFilteringInternal.instance; } } + internal static bool FilterByTab(IPackage package, PackageFilterTab tab) + { + switch (tab) + { + case PackageFilterTab.Modules: + return package.versions.Any(v => v.HasTag(PackageTag.BuiltIn) && !v.HasTag(PackageTag.AssetStore)); + case PackageFilterTab.All: + return package.versions.Any(v => !v.HasTag(PackageTag.BuiltIn) && !v.HasTag(PackageTag.AssetStore)) + && (package.isDiscoverable || (package.installedVersion?.isDirectDependency ?? false)); + case PackageFilterTab.Local: + return package.versions.Any(v => !v.HasTag(PackageTag.BuiltIn) && !v.HasTag(PackageTag.AssetStore)) + && (package.installedVersion?.isDirectDependency ?? false); + case PackageFilterTab.AssetStore: + return ApplicationUtil.instance.isUserLoggedIn && (package.primaryVersion?.HasTag(PackageTag.AssetStore) ?? false); + case PackageFilterTab.InDevelopment: + return package.installedVersion?.HasTag(PackageTag.InDevelopment) ?? false; + default: + return false; + } + } + + internal static bool FilterByText(IPackageVersion version, string text) + { + if (string.IsNullOrEmpty(text)) + return true; + + if (version == null) + return false; + + if (version.name.IndexOf(text, StringComparison.CurrentCultureIgnoreCase) >= 0) + return true; + + if (!string.IsNullOrEmpty(version.displayName) && version.displayName.IndexOf(text, StringComparison.CurrentCultureIgnoreCase) >= 0) + return true; + + if (!version.HasTag(PackageTag.BuiltIn)) + { + var prerelease = text.StartsWith("-") ? text.Substring(1) : text; + if (version.version != null && version.version.Prerelease.IndexOf(prerelease, StringComparison.CurrentCultureIgnoreCase) >= 0) + return true; + + if (version.version.StripTag().StartsWith(text, StringComparison.CurrentCultureIgnoreCase)) + return true; + + if (version.HasTag(PackageTag.Preview)) + { + if (PackageTag.Preview.ToString().IndexOf(text, StringComparison.CurrentCultureIgnoreCase) >= 0) + return true; + } + + if (version.HasTag(PackageTag.Verified)) + { + if (PackageTag.Verified.ToString().IndexOf(text, StringComparison.CurrentCultureIgnoreCase) >= 0) + return true; + } + + if (version.HasTag(PackageTag.Core)) + { + if (PackageTag.BuiltIn.ToString().IndexOf(text, StringComparison.CurrentCultureIgnoreCase) >= 0) + return true; + } + } + + if (version.HasTag(PackageTag.AssetStore)) + { + var words = text.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries); + var categories = version.category?.Split('/'); + if (categories != null && words.All(word => word.Length >= 2 && categories.Any(category => category.StartsWith(word, StringComparison.CurrentCultureIgnoreCase)))) + return true; + } + + return false; + } + [Serializable] private class PackageFilteringInternal : ScriptableSingleton, IPackageFiltering { + public event Action onFilterTabChanged = delegate {}; + public event Action onSearchTextChanged = delegate {}; + private PackageFilterTab m_CurrentFilterTab; public PackageFilterTab currentFilterTab { @@ -26,11 +103,10 @@ public PackageFilterTab currentFilterTab if (value != m_CurrentFilterTab) { m_CurrentFilterTab = value; - onFilterTabChanged(m_CurrentFilterTab); + onFilterTabChanged?.Invoke(m_CurrentFilterTab); } } } - public event Action onFilterTabChanged = delegate {}; private string m_CurrentSearchText; public string currentSearchText @@ -43,56 +119,13 @@ public string currentSearchText if (value != m_CurrentSearchText) { m_CurrentSearchText = value; - onSearchTextChanged(m_CurrentSearchText); + onSearchTextChanged?.Invoke(m_CurrentSearchText); } } } - public event Action onSearchTextChanged = delegate {}; private PackageFilteringInternal() {} - private static bool FilterByText(IPackageVersion version, string text) - { - if (version == null) - return false; - - if (version.name.IndexOf(text, StringComparison.CurrentCultureIgnoreCase) >= 0) - return true; - - if (!string.IsNullOrEmpty(version.displayName) && version.displayName.IndexOf(text, StringComparison.CurrentCultureIgnoreCase) >= 0) - return true; - - if (!version.HasTag(PackageTag.BuiltIn)) - { - var prerelease = text.StartsWith("-") ? text.Substring(1) : text; - if (version.version != null && version.version.Prerelease.IndexOf(prerelease, StringComparison.CurrentCultureIgnoreCase) >= 0) - return true; - - if (version.version.StripTag().StartsWith(text, StringComparison.CurrentCultureIgnoreCase)) - return true; - - if (version.HasTag(PackageTag.Preview)) - { - if (PackageTag.Preview.ToString().IndexOf(text, StringComparison.CurrentCultureIgnoreCase) >= 0) - return true; - } - - if (version.HasTag(PackageTag.Verified)) - { - if (PackageTag.Verified.ToString().IndexOf(text, StringComparison.CurrentCultureIgnoreCase) >= 0) - return true; - } - - if (version.HasTag(PackageTag.Core)) - { - if (PackageTag.BuiltIn.ToString().IndexOf(text, StringComparison.CurrentCultureIgnoreCase) >= 0) - return true; - } - } - - return false; - } - public bool FilterByCurrentSearchText(IPackage package) { if (string.IsNullOrEmpty(currentSearchText)) @@ -105,22 +138,7 @@ public bool FilterByCurrentSearchText(IPackage package) public bool FilterByCurrentTab(IPackage package) { - switch (currentFilterTab) - { - case PackageFilterTab.Modules: - return package.versions.Any(v => v.HasTag(PackageTag.BuiltIn)); - case PackageFilterTab.All: - return package.versions.Any(v => !v.HasTag(PackageTag.BuiltIn)) - && (package.isDiscoverable || (package.installedVersion?.isDirectDependency ?? false)); - case PackageFilterTab.Local: - return package.versions.Any(v => !v.HasTag(PackageTag.BuiltIn)) - && (package.installedVersion?.isDirectDependency ?? false); - case PackageFilterTab.InDevelopment: - return package.installedVersion?.HasTag(PackageTag.InDevelopment) ?? false; - default: - break; - } - return false; + return FilterByTab(package, currentFilterTab); } } } diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/PackageImage.cs b/Modules/PackageManagerUI/Editor/Services/Packages/PackageImage.cs new file mode 100644 index 0000000000..093a79459e --- /dev/null +++ b/Modules/PackageManagerUI/Editor/Services/Packages/PackageImage.cs @@ -0,0 +1,24 @@ +// 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.PackageManager.UI +{ + [Serializable] + internal class PackageImage + { + public enum ImageType + { + Main, + Screenshot, + Sketchfab, + Youtube, + } + + public ImageType type; + public string thumbnailUrl; + public string url; + } +} diff --git a/Modules/ParticleSystem/Managed/IParticleSystemJob.cs b/Modules/PackageManagerUI/Editor/Services/Packages/PackageLink.cs similarity index 51% rename from Modules/ParticleSystem/Managed/IParticleSystemJob.cs rename to Modules/PackageManagerUI/Editor/Services/Packages/PackageLink.cs index d509b145d0..bb6b1029a4 100644 --- a/Modules/ParticleSystem/Managed/IParticleSystemJob.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/PackageLink.cs @@ -2,12 +2,14 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License +using System; -namespace UnityEngine.Experimental.ParticleSystemJobs +namespace UnityEditor.PackageManager.UI { - public interface IParticleSystemJob + [Serializable] + internal class PackageLink { - void ProcessParticleSystem(ParticleSystemJobData jobData); + public string name; + public string url; } } - diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/PackageOrigin.cs b/Modules/PackageManagerUI/Editor/Services/Packages/PackageOrigin.cs index 0c7bed1be4..b6e474079c 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/PackageOrigin.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/PackageOrigin.cs @@ -8,6 +8,7 @@ internal enum PackageOrigin { Unknown, Builtin, - Registry + Registry, + AssetStore, } } diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/PackageSample.cs b/Modules/PackageManagerUI/Editor/Services/Packages/PackageSample.cs index 3ed1a17f22..8829caf5a2 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/PackageSample.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/PackageSample.cs @@ -155,15 +155,7 @@ internal string size if (string.IsNullOrEmpty(resolvedPath) || !Directory.Exists(resolvedPath)) return "0 KB"; var sizeInBytes = IOUtils.DirectorySizeInBytes(resolvedPath); - string[] sizes = { "KB", "MB", "GB", "TB" }; - double len = sizeInBytes / 1024.0; - int order = 0; - while (len >= 1024 && order < sizes.Length - 1) - { - order++; - len = len / 1024; - } - return $"{len:0.##} {sizes[order]}"; + return UIUtils.convertToHumanReadableSize(sizeInBytes); } } } diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/PackageSizeInfo.cs b/Modules/PackageManagerUI/Editor/Services/Packages/PackageSizeInfo.cs new file mode 100644 index 0000000000..44cf5e869a --- /dev/null +++ b/Modules/PackageManagerUI/Editor/Services/Packages/PackageSizeInfo.cs @@ -0,0 +1,16 @@ +// 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.PackageManager.UI +{ + [Serializable] + internal class PackageSizeInfo + { + public SemVersion supportedUnityVersion; + public ulong assetCount; + public ulong downloadSize; + } +} diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/PackageTag.cs b/Modules/PackageManagerUI/Editor/Services/Packages/PackageTag.cs index 685217f3c4..3afe5ca83f 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/PackageTag.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/PackageTag.cs @@ -7,7 +7,7 @@ namespace UnityEditor.PackageManager.UI { [Flags] - internal enum PackageTag : short + internal enum PackageTag : uint { None = 0, @@ -17,10 +17,13 @@ internal enum PackageTag : short Git = 1 << 2, BuiltIn = 1 << 3, Core = 1 << 4, + AssetStore = 1 << 5, + Published = 1 << 6, + Deprecated = 1 << 7, // preview status - Verified = 1 << 5, // the recommended version if major version > 0 - Preview = 1 << 6, // with `preview`, `preview.x` tag or with `0` as major version - Release = 1 << 7 // no pre-release tag & major version > 0 + Verified = 1 << 10, // the recommended version if major version > 0 + Preview = 1 << 11, // with `preview`, `preview.x` tag or with `0` as major version + Release = 1 << 12 // no pre-release tag & major version > 0 } } diff --git a/Modules/PackageManagerUI/Editor/Services/Upm/UpmBaseOperation.cs b/Modules/PackageManagerUI/Editor/Services/Upm/UpmBaseOperation.cs index 34d3bbb294..b3371585c1 100644 --- a/Modules/PackageManagerUI/Editor/Services/Upm/UpmBaseOperation.cs +++ b/Modules/PackageManagerUI/Editor/Services/Upm/UpmBaseOperation.cs @@ -83,11 +83,8 @@ protected void Start() protected void CancelInternal() { + OnFinalize(); m_Request = null; - onOperationError = delegate {}; - onOperationFinalized = delegate {}; - onProcessResult = delegate {}; - EditorApplication.update -= Progress; } // Common progress code for all classes diff --git a/Modules/PackageManagerUI/Editor/Services/Upm/UpmClient.cs b/Modules/PackageManagerUI/Editor/Services/Upm/UpmClient.cs index bf52bb2e01..e780f1ad7d 100644 --- a/Modules/PackageManagerUI/Editor/Services/Upm/UpmClient.cs +++ b/Modules/PackageManagerUI/Editor/Services/Upm/UpmClient.cs @@ -69,6 +69,9 @@ private void AddExtraPackageInfo(PackageInfo packageInfo) private PackageInfo[] m_SerializedSearchPackageInfos; private PackageInfo[] m_SerializedExtraPackageInfos; + [SerializeField] + private bool m_SetupDone; + public bool isAddRemoveOrEmbedInProgress { get { return m_AddOperation.isInProgress || m_RemoveOperation.isInProgress || m_EmbedOperation.isInProgress; } @@ -138,32 +141,23 @@ private void OnProcessAddResult(Request request) public void AddByPath(string path) { - var packageId = GetPackageIdFromPath(path); - if (string.IsNullOrEmpty(packageId)) - { - Debug.LogError($"Error loading package id from path: \"{path}\"."); + if (isAddRemoveOrEmbedInProgress) return; - } - AddById(packageId); - } - - private string GetPackageIdFromPath(string path) - { - var jsonPath = Directory.Exists(path) ? Path.Combine(path, "package.json") : path; - if (!File.Exists(jsonPath)) - return null; - try + path = path.Replace('\\', '/'); + var projectPath = Path.GetDirectoryName(Application.dataPath).Replace('\\', '/') + '/'; + if (path.StartsWith(projectPath)) { - var packageJson = Json.Deserialize(File.ReadAllText(jsonPath)) as Dictionary; - var name = packageJson["name"] as string; - var directoryPath = Path.GetDirectoryName(jsonPath).Replace("\\", "/"); - return $"{name}@file:{directoryPath}"; - } - catch (Exception) - { - return null; + var packageFolderPrefix = "Packages/"; + var relativePathToProjectRoot = path.Substring(projectPath.Length); + if (relativePathToProjectRoot.StartsWith(packageFolderPrefix, StringComparison.InvariantCultureIgnoreCase)) + path = relativePathToProjectRoot.Substring(packageFolderPrefix.Length); + else + path = $"../{relativePathToProjectRoot}"; } + + m_AddOperation.AddByUrlOrPath($"file:{path}"); + SetupAddOperation(); } public void AddByUrl(string url) @@ -174,6 +168,7 @@ public void AddByUrl(string url) // convert SCP-like syntax to SSH URL as currently UPM doesn't support it if (url.ToLower().StartsWith("git@")) url = "ssh://" + url.Replace(':', '/'); + m_AddOperation.AddByUrlOrPath(url); SetupAddOperation(); } @@ -508,11 +503,19 @@ public void OnEnable() public void Setup() { + System.Diagnostics.Debug.Assert(!m_SetupDone); + m_SetupDone = true; + PackageManagerPrefs.instance.onShowPreviewPackagesChanged += OnShowPreviewPackagesChanged; } public void Clear() { + System.Diagnostics.Debug.Assert(m_SetupDone); + m_SetupDone = false; + + PackageManagerPrefs.instance.onShowPreviewPackagesChanged -= OnShowPreviewPackagesChanged; + m_InstalledPackageInfos.Clear(); m_SearchPackageInfos.Clear(); m_ExtraPackageInfo.Clear(); diff --git a/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackage.cs b/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackage.cs index 718ef28175..2b66a50fc4 100644 --- a/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackage.cs +++ b/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackage.cs @@ -102,8 +102,11 @@ public IPackageVersion recommendedVersion public IPackageVersion primaryVersion { get { return installedVersion ?? recommendedVersion; } } // errors on the package level (not just about a particular version) - private List m_Errors; - public IEnumerable errors { get { return m_Errors; } } + List m_UpmErrors; + + // Combined errors for this package or any version. + // Stop lookup after first error encountered on a version to save time not looking up redundant errors. + public IEnumerable errors => (versions.Select(v => v.errors).FirstOrDefault(e => e?.Any() ?? false) ?? new List()).Concat(m_UpmErrors); public UpmPackage(string name, IEnumerable versions, bool isDiscoverable) { @@ -125,7 +128,7 @@ private void Initialize(string name, IEnumerable versions, bo m_Versions = versions.ToList(); m_IsDiscoverable = isDiscoverable; - m_Errors = new List(); + m_UpmErrors = new List(); SetInstalledVersion(m_Versions.FindIndex(v => v.isInstalled)); } @@ -203,12 +206,17 @@ public void RemoveInstalledVersion() public void AddError(Error error) { - m_Errors.Add(error); + m_UpmErrors.Add(error); } public void ClearErrors() { - m_Errors.Clear(); + m_UpmErrors.Clear(); + } + + public IPackage Clone() + { + return (IPackage)MemberwiseClone(); } } } diff --git a/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackageDocs.cs b/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackageDocs.cs index 84d6645665..2925e2b46f 100644 --- a/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackageDocs.cs +++ b/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackageDocs.cs @@ -77,7 +77,9 @@ private static string GetOfflineDocumentationUrl(UpmPackageVersion version) docsFolder = Path.Combine(version.packageInfo.resolvedPath, "Documentation"); if (Directory.Exists(docsFolder)) { - var docsMd = Directory.GetFiles(docsFolder, "*.md", SearchOption.TopDirectoryOnly).FirstOrDefault(); + var mdFiles = Directory.GetFiles(docsFolder, "*.md", SearchOption.TopDirectoryOnly); + var docsMd = mdFiles.FirstOrDefault(d => Path.GetFileName(d).ToLower() == "index.md") + ?? mdFiles.FirstOrDefault(d => Path.GetFileName(d).ToLower() == "tableofcontents.md") ?? mdFiles.FirstOrDefault(); if (!string.IsNullOrEmpty(docsMd)) return new Uri(docsMd).AbsoluteUri; } diff --git a/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackageVersion.cs b/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackageVersion.cs index c664ee8cb3..1b9fae77af 100644 --- a/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackageVersion.cs +++ b/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackageVersion.cs @@ -22,10 +22,14 @@ internal class UpmPackageVersion : IPackageVersion public string name { get { return m_PackageInfo.name; } } public string type { get { return m_PackageInfo.type; } } public string category { get { return m_PackageInfo.category; } } - public IEnumerable errors { get { return m_PackageInfo.errors; } } + public IEnumerable errors => m_PackageInfo.errors.Concat(entitlementsError != null ? new List { entitlementsError } : new List()); public bool isDirectDependency { get { return isFullyFetched && m_PackageInfo.isDirectDependency; } } + public DependencyInfo[] dependencies { get { return m_PackageInfo.dependencies; } } public DependencyInfo[] resolvedDependencies { get { return m_PackageInfo.resolvedDependencies; } } + public EntitlementsInfo entitlements => m_PackageInfo.entitlements; + Error entitlementsError => !entitlements.isAllowed && isInstalled ? new Error(NativeErrorCode.Unknown, L10n.Tr("You do not have entitlements for this package.")) : null; + private string m_PackageId; public string uniqueId { get { return m_PackageId; } } @@ -116,13 +120,13 @@ public bool isInstalled } } - [SerializeField] - public bool isUserVisible { get { return isInstalled || HasTag(PackageTag.Release | PackageTag.Preview | PackageTag.Verified | PackageTag.Core);; } } + public bool isUserVisible { get { return isInstalled || HasTag(PackageTag.Release | PackageTag.Preview | PackageTag.Verified | PackageTag.Core); } } private string m_Description; public string description { get { return !string.IsNullOrEmpty(m_Description) ? m_Description : m_PackageInfo.description; } } private PackageTag m_Tag; + public bool HasTag(PackageTag tag) { return (m_Tag & tag) != 0; @@ -158,7 +162,32 @@ public bool isAvailableOnDisk public string shortVersionId { get { return FormatPackageId(name, version.ShortVersion()); } } - public DateTime? datePublished { get { return m_PackageInfo.datePublished; } } + public DateTime? publishedDate { get { return m_PackageInfo.datePublished; } } + + public string publisherId => m_Author; + + public string localPath + { + get + { + var packageInfoResolvedPath = packageInfo?.resolvedPath; + return packageInfoResolvedPath; + } + } + + public string versionString => m_Version?.ToString(); + + public string versionId => m_Version?.ToString(); + + public SemVersion supportedVersion => null; + + public IEnumerable supportedVersions => Enumerable.Empty(); + + public IEnumerable images => Enumerable.Empty(); + + public IEnumerable sizes => Enumerable.Empty(); + + public IEnumerable links => Enumerable.Empty(); public UpmPackageVersion(PackageInfo packageInfo, bool isInstalled, SemVersion version, string displayName) { diff --git a/Modules/PackageManagerUI/Editor/UI/Common/Alert.cs b/Modules/PackageManagerUI/Editor/UI/Common/Alert.cs index 87ca71d971..28c62d4a34 100644 --- a/Modules/PackageManagerUI/Editor/UI/Common/Alert.cs +++ b/Modules/PackageManagerUI/Editor/UI/Common/Alert.cs @@ -22,7 +22,6 @@ public Alert() var root = Resources.GetTemplate("Alert.uxml"); Add(root); - root.StretchToParentSize(); cache = new VisualElementCache(root); @@ -46,19 +45,10 @@ public void SetError(Error error) public void ClearError() { UIUtils.SetElementDisplay(this, false); - AdjustSize(false); alertMessage.text = ""; onCloseError = null; } - public void AdjustSize(bool verticalScrollerVisible) - { - if (verticalScrollerVisible) - style.right = k_PositionRightOriginal + k_PositionRightWithScroll; - else - style.right = k_PositionRightOriginal; - } - private VisualElementCache cache { get; set; } private Label alertMessage { get { return cache.Get