diff --git a/Editor/IncrementalBuildPipeline/BeeBuildProgramCommon.Data/Data.cs b/Editor/IncrementalBuildPipeline/BeeBuildProgramCommon.Data/Data.cs index 6e100ee65e..0a7938fabc 100644 --- a/Editor/IncrementalBuildPipeline/BeeBuildProgramCommon.Data/Data.cs +++ b/Editor/IncrementalBuildPipeline/BeeBuildProgramCommon.Data/Data.cs @@ -34,7 +34,6 @@ public class ConfigurationData public string UnityVersion; public Version UnityVersionNumeric; public string UnitySourceCodePath; - public bool AdvancedLicense; public bool Batchmode; public bool EmitDataForBeeWhy; public string NamedPipeOrUnixSocket; diff --git a/Editor/Mono/Animation/AnimationWindow/CurveBindingUtility.cs b/Editor/Mono/Animation/AnimationWindow/CurveBindingUtility.cs index 05000b27e2..6678280c1d 100644 --- a/Editor/Mono/Animation/AnimationWindow/CurveBindingUtility.cs +++ b/Editor/Mono/Animation/AnimationWindow/CurveBindingUtility.cs @@ -29,7 +29,10 @@ public static object GetCurrentValue(AnimationWindowState state, EditorCurveBind // Otherwise, evaluate AnimationWindowCurve at current time. public static object GetCurrentValue(AnimationWindowState state, AnimationWindowCurve curve) { - if (state.previewing && curve.rootGameObject != null) + // UUM-66112 - state.linkedWithSequencer - Padding for issue in Timeline where muscle + // values are not updated in the editor when previewing in the Animation Window. + // Fallback to curve values. + if (state.previewing && curve.rootGameObject != null && !state.linkedWithSequencer) { return GetCurrentValue(state, curve.binding); } diff --git a/Editor/Mono/Annotation/SceneRenderModeWindow.cs b/Editor/Mono/Annotation/SceneRenderModeWindow.cs index e13ab71850..38cb99b119 100644 --- a/Editor/Mono/Annotation/SceneRenderModeWindow.cs +++ b/Editor/Mono/Annotation/SceneRenderModeWindow.cs @@ -138,7 +138,7 @@ static class Styles new SceneView.CameraMode(DrawCameraMode.AlphaChannel, "Alpha Channel", kMiscellaneous), new SceneView.CameraMode(DrawCameraMode.Overdraw, "Overdraw", kMiscellaneous), new SceneView.CameraMode(DrawCameraMode.Mipmaps, "Mipmaps", kMiscellaneous), - new SceneView.CameraMode(DrawCameraMode.TextureStreaming, "Texture Streaming", kMiscellaneous), + new SceneView.CameraMode(DrawCameraMode.TextureStreaming, "Texture Mipmap Streaming", kMiscellaneous), new SceneView.CameraMode(DrawCameraMode.SpriteMask, "Sprite Mask", kMiscellaneous), new SceneView.CameraMode(DrawCameraMode.ValidateAlbedo, "Validate Albedo", kMiscellaneous), new SceneView.CameraMode(DrawCameraMode.ValidateMetalSpecular, "Validate Metal Specular", kMiscellaneous), @@ -163,7 +163,7 @@ private float windowHeight modes = Styles.sBuiltinCameraModes.Count(mode => m_SceneView.IsCameraDrawModeSupported(mode) && mode.show) + SceneView.userDefinedModes.Count(mode => m_SceneView.IsCameraDrawModeSupported(mode) && mode.show); - return UpdatedHeight(headers, modes, GraphicsSettings.renderPipelineAsset != null); + return UpdatedHeight(headers, modes, GraphicsSettings.isScriptableRenderPipelineEnabled); } } @@ -295,7 +295,7 @@ private void Draw(float listElementWidth) } } - if (GraphicsSettings.renderPipelineAsset != null) + if (GraphicsSettings.isScriptableRenderPipelineEnabled) { DrawSeparator(ref drawPos); DrawRenderingDebuggerShortCut(drawPos); @@ -339,7 +339,7 @@ private float RecalculateWindowHeight() } } - return UpdatedHeight(headers, modes, GraphicsSettings.renderPipelineAsset != null); + return UpdatedHeight(headers, modes, GraphicsSettings.isScriptableRenderPipelineEnabled); } private float UpdatedHeight(int headers, int modes, bool isSRP) diff --git a/Editor/Mono/AssemblyInfo/AssemblyInfo.cs b/Editor/Mono/AssemblyInfo/AssemblyInfo.cs index 8a0bc40e87..d1b7474c8d 100644 --- a/Editor/Mono/AssemblyInfo/AssemblyInfo.cs +++ b/Editor/Mono/AssemblyInfo/AssemblyInfo.cs @@ -153,6 +153,9 @@ [assembly: InternalsVisibleTo("Unity.Muse.Common.Bridge")] [assembly: InternalsVisibleTo("Unity.Muse.Chat.Bridge")] +[assembly: InternalsVisibleTo("Unity.Multiplayer.Playmode.Editor.Bridge")] +[assembly: InternalsVisibleTo("Unity.DedicatedServer.Editor.Bridge")] + [assembly: InternalsVisibleTo("Unity.Scenes")] // This should move with the AnimationWindow to a module at some point diff --git a/Editor/Mono/AssetPipeline/TextureGenerator.bindings.cs b/Editor/Mono/AssetPipeline/TextureGenerator.bindings.cs index 9ccb5d0de8..7c1eb764c4 100644 --- a/Editor/Mono/AssetPipeline/TextureGenerator.bindings.cs +++ b/Editor/Mono/AssetPipeline/TextureGenerator.bindings.cs @@ -248,11 +248,16 @@ public static unsafe class TextureGenerator { public static TextureGenerationOutput GenerateTexture(TextureGenerationSettings settings, NativeArray colorBuffer) { - return GenerateTextureImpl(settings, colorBuffer.GetUnsafeReadOnlyPtr(), colorBuffer.Length * UnsafeUtility.SizeOf()); + return GenerateTextureImpl(settings, colorBuffer.GetUnsafeReadOnlyPtr(), colorBuffer.Length * UnsafeUtility.SizeOf(), 4); + } + + public static TextureGenerationOutput GenerateTexture(TextureGenerationSettings settings, NativeArray colorBuffer) + { + return GenerateTextureImpl(settings, colorBuffer.GetUnsafeReadOnlyPtr(), colorBuffer.Length * UnsafeUtility.SizeOf(), 16); } [NativeThrows] [NativeMethod("GenerateTextureScripting")] - extern static unsafe TextureGenerationOutput GenerateTextureImpl(TextureGenerationSettings settings, void* colorBuffer, int colorBufferLength); + extern static unsafe TextureGenerationOutput GenerateTextureImpl(TextureGenerationSettings settings, void* colorBuffer, int colorBufferLength, int bytesPerPixel); } } diff --git a/Editor/Mono/Audio/AudioContainerWindow.cs b/Editor/Mono/Audio/AudioContainerWindow.cs index 277b9f74d2..a556808e2d 100644 --- a/Editor/Mono/Audio/AudioContainerWindow.cs +++ b/Editor/Mono/Audio/AudioContainerWindow.cs @@ -139,6 +139,14 @@ void OnDisable() m_AddedElements.Clear(); } + private void OnFocus() + { + if (State.AudioContainer != null) + { + UpdateTransportButtonStates(); + } + } + void Update() { if (!m_IsVisible) @@ -232,6 +240,7 @@ void CreateGUI() m_Day0RootVisualElement.style.display = DisplayStyle.None; m_ContainerRootVisualElement.style.display = DisplayStyle.Flex; + m_CachedElements = State.AudioContainer.elements.ToList(); m_ClipsListView.Rebuild(); // Force a list rebuild when the list has changed or it will not always render correctly due to a UI toolkit bug. } } @@ -519,12 +528,14 @@ void OnVolumeRandomizationEnabledChanged(SerializedProperty property) m_VolumeRandomizationButtonImage.style.backgroundImage = new StyleBackground(m_DiceIconOn); m_VolumeRandomizationRangeSlider.SetEnabled(true); m_VolumeRandomizationRangeField.SetEnabled(true); + m_VolumeRandomRangeTracker.SetEnabled(true); } else { m_VolumeRandomizationButtonImage.style.backgroundImage = new StyleBackground(m_DiceIconOff); m_VolumeRandomizationRangeSlider.SetEnabled(false); m_VolumeRandomizationRangeField.SetEnabled(false); + m_VolumeRandomRangeTracker.SetEnabled(false); } } @@ -624,12 +635,14 @@ void OnPitchRandomizationEnabledChanged(SerializedProperty property) m_PitchRandomizationButtonImage.style.backgroundImage = new StyleBackground(m_DiceIconOn); m_PitchRandomizationRangeSlider.SetEnabled(true); m_PitchRandomizationRangeField.SetEnabled(true); + m_PitchRandomRangeTracker.SetEnabled(true); } else { m_PitchRandomizationButtonImage.style.backgroundImage = new StyleBackground(m_DiceIconOff); m_PitchRandomizationRangeSlider.SetEnabled(false); m_PitchRandomizationRangeField.SetEnabled(false); + m_PitchRandomRangeTracker.SetEnabled(false); } } @@ -1190,12 +1203,14 @@ void OnTimeRandomizationEnabledChanged(SerializedProperty property) m_TimeRandomizationButtonImage.style.backgroundImage = new StyleBackground(m_DiceIconOn); m_TimeRandomizationRangeSlider.SetEnabled(true); m_TimeRandomizationRangeField.SetEnabled(true); + m_TimeRandomRangeTracker.SetEnabled(true); } else { m_TimeRandomizationButtonImage.style.backgroundImage = new StyleBackground(m_DiceIconOff); m_TimeRandomizationRangeSlider.SetEnabled(false); m_TimeRandomizationRangeField.SetEnabled(false); + m_TimeRandomRangeTracker.SetEnabled(false); } } diff --git a/Editor/Mono/Audio/UIElements/AudioRandomRangeSliderTracker.cs b/Editor/Mono/Audio/UIElements/AudioRandomRangeSliderTracker.cs index bf56d907c9..f28220c9b7 100644 --- a/Editor/Mono/Audio/UIElements/AudioRandomRangeSliderTracker.cs +++ b/Editor/Mono/Audio/UIElements/AudioRandomRangeSliderTracker.cs @@ -3,6 +3,7 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; +using System.Transactions; using UnityEngine; using UnityEngine.UIElements; @@ -16,11 +17,12 @@ class AudioRandomRangeSliderTracker : VisualElement public override object CreateInstance() => new AudioRandomRangeSliderTracker(); } - static readonly CustomStyleProperty s_TrackerColorProperty = new("--tracker-color"); + static readonly CustomStyleProperty s_TrackerEnabledColorProperty = new("--tracker-color"); Slider m_ParentSlider; Vector2 m_Range = Vector2.zero; - Color m_TrackerColor; + Color m_TrackerEnabledColor; + Color m_TrackerDisabledColor = Color.gray; static void CustomStylesResolved(CustomStyleResolvedEvent evt) { @@ -31,9 +33,9 @@ static void CustomStylesResolved(CustomStyleResolvedEvent evt) void UpdateCustomStyles() { - if (customStyle.TryGetValue(s_TrackerColorProperty, out var trackerColor)) + if (customStyle.TryGetValue(s_TrackerEnabledColorProperty, out var trackerColor)) { - m_TrackerColor = trackerColor; + m_TrackerEnabledColor = trackerColor; } } @@ -54,6 +56,7 @@ internal static AudioRandomRangeSliderTracker Create(Slider parentSlider, Vector rangeTracker.generateVisualContent += GenerateVisualContent; rangeTracker.RegisterCallback(CustomStylesResolved); rangeTracker.m_ParentSlider.RegisterCallback(OnGeometryChanged); + rangeTracker.RegisterCallback(OnPropertyChanged); return rangeTracker; } @@ -72,6 +75,16 @@ static void OnGeometryChanged(GeometryChangedEvent evt) sliderTracker.SetRange(sliderTracker.m_Range); } + static void OnPropertyChanged(PropertyChangedEvent evt) + { + var sliderTracker = evt.elementTarget; + + if (evt.property == "enabledSelf") + { + sliderTracker.MarkDirtyRepaint(); + } + } + // Maps 'x' from the range '[x_min; x_max]' to the range '[y_min; y_max]'. static float Map(float x, float x_min, float x_max, float y_min, float y_max) { @@ -102,7 +115,7 @@ static void GenerateVisualContent(MeshGenerationContext context) right = Mathf.Clamp(right, contentRect.xMin, contentRect.xMax); // Draw the tracker. - painter2D.fillColor = sliderTracker.m_TrackerColor; + painter2D.fillColor = sliderTracker.enabledSelf ? sliderTracker.m_TrackerEnabledColor : sliderTracker.m_TrackerDisabledColor; painter2D.BeginPath(); painter2D.MoveTo(new Vector2(left, contentRect.yMin)); painter2D.LineTo(new Vector2(right, contentRect.yMin)); diff --git a/Editor/Mono/BaseBuildTarget.cs b/Editor/Mono/BaseBuildTarget.cs index 673582544e..98fc1b3fb0 100644 --- a/Editor/Mono/BaseBuildTarget.cs +++ b/Editor/Mono/BaseBuildTarget.cs @@ -18,6 +18,8 @@ internal abstract class BaseBuildTarget : IBuildTarget public abstract RuntimePlatform RuntimePlatform { get; } public abstract string TargetName { get; } + public abstract GUID Guid { get; } + public abstract int GetLegacyId { get; } public virtual IBuildPlatformProperties BuildPlatformProperties => Properties as IBuildPlatformProperties; diff --git a/Editor/Mono/BuildPipeline.bindings.cs b/Editor/Mono/BuildPipeline.bindings.cs index 1189069831..d33a4519ee 100644 --- a/Editor/Mono/BuildPipeline.bindings.cs +++ b/Editor/Mono/BuildPipeline.bindings.cs @@ -12,6 +12,7 @@ using UnityEditor.Scripting.ScriptCompilation; using System.Runtime.InteropServices; using UnityEditor.Build; +using UnityEditor.Build.Profile; using UnityEngine.Scripting; namespace UnityEditor @@ -223,6 +224,14 @@ public struct BuildPlayerOptions public string[] extraScriptingDefines { get; set; } } + public struct BuildPlayerWithProfileOptions + { + public BuildProfile buildProfile { get; set; } + public string locationPathName { get; set; } + public string assetBundleManifestPath { get; set; } + public BuildOptions options { get; set; } + } + internal struct BuildPlayerDataOptions { public string[] scenes { get; set; } @@ -276,6 +285,10 @@ public class BuildPipeline [FreeFunction(IsThreadSafe = true)] internal static extern string GetEditorTargetName(); + [NativeHeader("Editor/Src/BuildPipeline/BuildPlayerHelpers.h")] + [FreeFunction] + internal static extern void ShowBuildProfileWindow(); + [Obsolete("PushAssetDependencies has been made obsolete. Please use the new AssetBundle build system introduced in 5.0 and check BuildAssetBundles documentation for details.", true)] [FreeFunction] public static extern void PushAssetDependencies(); @@ -302,6 +315,24 @@ internal static BuildPlayerContext PreparePlayerBuild(BuildPlayerOptions buildPl return buildPlayerContext; } + /// + /// Builds a player. + /// + /// The BuildPlayerWithProfileOptions to be built with. + /// A BuildReport giving build process information. + /// Throws if build profile is null. + public static BuildReport BuildPlayer(BuildPlayerWithProfileOptions buildPlayerWithProfileOptions) + { + var buildProfile = buildPlayerWithProfileOptions.buildProfile; + if (buildProfile == null) + throw new ArgumentException("Build profile is invalid."); + + BuildProfileContext.instance.activeProfile = buildProfile; + var buildPlayerOptions = BuildProfileModuleUtil.GetBuildPlayerOptionsFromActiveProfile( + buildPlayerWithProfileOptions.locationPathName, buildPlayerWithProfileOptions.assetBundleManifestPath, buildPlayerWithProfileOptions.options); + return BuildPlayer(buildPlayerOptions); + } + public static BuildReport BuildPlayer(EditorBuildSettingsScene[] levels, string locationPathName, BuildTarget target, BuildOptions options) { BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions(); diff --git a/Editor/Mono/BuildPipeline/BuildPlatform.cs b/Editor/Mono/BuildPipeline/BuildPlatform.cs index a7a9ba1833..bc53999930 100644 --- a/Editor/Mono/BuildPipeline/BuildPlatform.cs +++ b/Editor/Mono/BuildPipeline/BuildPlatform.cs @@ -3,6 +3,7 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using UnityEngine; +using System; using System.Collections.Generic; using DiscoveredTargetInfo = UnityEditor.BuildTargetDiscovery.DiscoveredTargetInfo; using TargetAttributes = UnityEditor.BuildTargetDiscovery.TargetAttributes; @@ -10,7 +11,7 @@ namespace UnityEditor.Build { // All settings for a build platform. - internal class BuildPlatform + internal class BuildPlatform : ICloneable { // short name used for texture settings, etc. public string name; @@ -38,13 +39,24 @@ public BuildPlatform(string locTitle, string tooltip, string iconId, NamedBuildT { this.namedBuildTarget = namedBuildTarget; name = namedBuildTarget.TargetName; - m_Title = new ScalableGUIContent(locTitle, null, iconId); + + // Workaround for some platforms which have | in their name which is also used as separator for tooltips + if (locTitle.Contains("|")) + m_Title = new ScalableGUIContent(locTitle.Replace("|", " "), null, iconId); + else + m_Title = new ScalableGUIContent(locTitle, null, iconId); + m_SmallTitle = new ScalableGUIContent(null, null, iconId + ".Small"); this.tooltip = tooltip; this.hideInUi = hideInUi; this.defaultTarget = defaultTarget; this.installed = installed; } + + public object Clone() + { + return MemberwiseClone(); + } } internal class BuildPlatformWithSubtarget : BuildPlatform @@ -132,29 +144,10 @@ public string GetBuildTargetDisplayName(NamedBuildTarget namedBuildTarget, Build } var suffix = namedBuildTarget == NamedBuildTarget.Server ? " Server" : ""; - - switch (target) - { - case BuildTarget.StandaloneWindows: - case BuildTarget.StandaloneWindows64: - return $"Windows{suffix}"; - case BuildTarget.StandaloneOSX: - // Deprecated -#pragma warning disable 612, 618 - case BuildTarget.StandaloneOSXIntel: - case BuildTarget.StandaloneOSXIntel64: -#pragma warning restore 612, 618 - return $"macOS{suffix}"; - // Deprecated -#pragma warning disable 612, 618 - case BuildTarget.StandaloneLinux: - case BuildTarget.StandaloneLinuxUniversal: -#pragma warning restore 612, 618 - case BuildTarget.StandaloneLinux64: - return $"Linux{suffix}"; - } - - return "Unsupported Target"; +#pragma warning disable CS0618 // Member is obsolete + string targetName = BuildTargetDiscovery.BuildPlatformDisplayName(target) + suffix; +#pragma warning restore CS0618 + return targetName.Length == 0 ? "Unsupported Target" : targetName; } public string GetModuleDisplayName(NamedBuildTarget namedBuildTarget, BuildTarget buildTarget) diff --git a/Editor/Mono/BuildPipeline/DataBuildDirtyTracker.cs b/Editor/Mono/BuildPipeline/DataBuildDirtyTracker.cs index d30d6fdc0b..0515812988 100644 --- a/Editor/Mono/BuildPipeline/DataBuildDirtyTracker.cs +++ b/Editor/Mono/BuildPipeline/DataBuildDirtyTracker.cs @@ -39,6 +39,7 @@ class BuildData { public BuildDataInputFile[] scenes; public BuildDataInputFile[] inputFiles; + public BuildDataInputFile activeBuildProfile; public string[] enabledModules; public string[] resourcePaths; public BuildOptions buildOptions; @@ -54,6 +55,7 @@ class BuildData private BuildData buildData; private string[] scenes; + private NPath activeBuildProfilePath; public BuildOptions buildOptions; bool CheckAssetDirty(BuildDataInputFile file) @@ -135,12 +137,18 @@ bool DoCheckDirty() return true; } + if ((activeBuildProfilePath != buildData.activeBuildProfile.path) || (!string.IsNullOrEmpty(buildData.activeBuildProfile.path) && CheckAssetDirty(buildData.activeBuildProfile))) + { + Console.WriteLine($"Rebuilding Data files because the active build profile have changed"); + return true; + } + Console.WriteLine("Not rebuilding Data files -- no changes"); return false; } [RequiredByNativeCode] - static public void WriteBuildData(string buildDataPath, BuildReport report, string[] scenes, string[] prefabs) + static public void WriteBuildData(string buildDataPath, BuildReport report, string[] scenes, string[] prefabs, string activeBuildProfilePath) { var developmentBuild = report.summary.options.HasFlag(BuildOptions.Development); var inputScenes = new List(); @@ -164,6 +172,7 @@ static public void WriteBuildData(string buildDataPath, BuildReport report, stri { scenes = inputScenes.ToArray(), inputFiles = inputFiles.ToArray(), + activeBuildProfile = new BuildDataInputFile(activeBuildProfilePath, developmentBuild), buildOptions = report.summary.options & BuildData.BuildOptionsMask, unityVersion = Application.unityVersion, resourcePaths = ResourcesAPIInternal.GetAllPaths("").OrderBy(p => p).ToArray(), @@ -175,7 +184,7 @@ static public void WriteBuildData(string buildDataPath, BuildReport report, stri } [RequiredByNativeCode] - static public bool CheckDirty(string buildDataPath, BuildOptions buildOptions, string[] scenes) + static public bool CheckDirty(string buildDataPath, BuildOptions buildOptions, string[] scenes, string activeBuildProfilePath) { NPath buildReportPath = buildDataPath; if (!buildReportPath.FileExists()) @@ -187,6 +196,7 @@ static public bool CheckDirty(string buildDataPath, BuildOptions buildOptions, s { buildData = JsonUtility.FromJson(buildReportPath.ReadAllText()), scenes = scenes, + activeBuildProfilePath = activeBuildProfilePath, buildOptions = buildOptions }; return tracker.DoCheckDirty(); diff --git a/Editor/Mono/BuildPipeline/NamedBuildTarget.cs b/Editor/Mono/BuildPipeline/NamedBuildTarget.cs index b084b65fee..c27727ca51 100644 --- a/Editor/Mono/BuildPipeline/NamedBuildTarget.cs +++ b/Editor/Mono/BuildPipeline/NamedBuildTarget.cs @@ -142,6 +142,26 @@ internal static NamedBuildTarget FromActiveSettings(BuildTarget target) return NamedBuildTarget.FromBuildTargetGroup(buildTargetGroup); } + internal static NamedBuildTarget FromTargetAndSubtarget(BuildTarget target, int subtarget) + { + var buildTargetGroup = BuildPipeline.GetBuildTargetGroup(target); + if (buildTargetGroup == BuildTargetGroup.Standalone) + { + var standaloneSubtarget = (StandaloneBuildSubtarget)subtarget; + switch (standaloneSubtarget) + { + case StandaloneBuildSubtarget.Player: + return NamedBuildTarget.Standalone; + case StandaloneBuildSubtarget.Server: + return NamedBuildTarget.Server; + default: + throw new ArgumentException($"'{standaloneSubtarget}' is not a valid subtarget for the Standalone build target"); + } + } + + return NamedBuildTarget.FromBuildTargetGroup(buildTargetGroup); + } + public static bool operator==(NamedBuildTarget lhs, NamedBuildTarget rhs) { return lhs.Equals(rhs); diff --git a/Editor/Mono/BuildPlayerWindow.cs b/Editor/Mono/BuildPlayerWindow.cs index 8ec3a359db..005edefc65 100644 --- a/Editor/Mono/BuildPlayerWindow.cs +++ b/Editor/Mono/BuildPlayerWindow.cs @@ -20,6 +20,7 @@ using RequiredByNativeCodeAttribute = UnityEngine.Scripting.RequiredByNativeCodeAttribute; using UnityEditor.Connect; using UnityEditor.Utils; +using UnityEditor.Build.Profile; namespace UnityEditor { @@ -151,7 +152,7 @@ static Styles() static bool isEditorinstalledWithHub = IsEditorInstalledWithHub(); - internal static event Action drawingMultiplayerBuildOptions; + internal static event Action drawingMultiplayerBuildOptions; [UsedImplicitly, RequiredByNativeCode] public static void ShowBuildPlayerWindow() @@ -162,9 +163,9 @@ public static void ShowBuildPlayerWindow() internal static bool WillDrawMultiplayerBuildOptions() => drawingMultiplayerBuildOptions != null; - internal static void DrawMultiplayerBuildOption(NamedBuildTarget namedBuildTarget) + internal static void DrawMultiplayerBuildOption(BuildProfile buildProfile) { - drawingMultiplayerBuildOptions?.Invoke(namedBuildTarget); + drawingMultiplayerBuildOptions?.Invoke(buildProfile); } static bool BuildLocationIsValid(string path) @@ -582,7 +583,9 @@ static bool IsVirtualTexturingSettingsValid(BuildPlatform platform) }; static public string GetPlaybackEngineDownloadURL(string moduleName) { - if (moduleName == "PS4" || moduleName == "PS5" || moduleName == "XboxOne") +#pragma warning disable CS0618 // Member is obsolete + if (!BuildTargetDiscovery.BuildPlatformCanBeInstalledWithHub(BuildTargetDiscovery.GetBuildTargetByName(moduleName))) +#pragma warning restore CS0618 return "https://unity3d.com/platform-installation"; string fullVersion = InternalEditorUtility.GetFullUnityVersion(); @@ -939,7 +942,13 @@ void ShowBuildTargetSettings() GUILayout.EndHorizontal(); } - drawingMultiplayerBuildOptions?.Invoke(namedBuildTarget); + var subtarget = StandaloneBuildSubtarget.Default; + if (namedBuildTarget == NamedBuildTarget.Standalone) + subtarget = StandaloneBuildSubtarget.Player; + else if (namedBuildTarget == NamedBuildTarget.Server) + subtarget = StandaloneBuildSubtarget.Server; + + drawingMultiplayerBuildOptions?.Invoke(BuildProfileContext.instance.GetForClassicPlatform(buildTarget, subtarget)); GUILayout.EndScrollView(); @@ -958,8 +967,9 @@ internal static void ShowNoModuleLabel( { GUILayout.Label(EditorGUIUtility.TextContent(string.Format(noModuleLoaded, BuildPlatforms.instance.GetModuleDisplayName(namedBuildTarget, buildTarget)))); string url = ""; - - if (!isEditorinstalledWithHub || (moduleName == "PS4" || moduleName == "PS5" || moduleName == "XboxOne")) +#pragma warning disable CS0618 // Member is obsolete + if (!isEditorinstalledWithHub || !BuildTargetDiscovery.BuildPlatformCanBeInstalledWithHub(buildTarget)) +#pragma warning restore CS0618 { if (GUILayout.Button(openDownloadPage, EditorStyles.miniButton, GUILayout.ExpandWidth(false))) { diff --git a/Editor/Mono/BuildPlayerWindowBuildMethods.cs b/Editor/Mono/BuildPlayerWindowBuildMethods.cs index 35231b3343..3799963f17 100644 --- a/Editor/Mono/BuildPlayerWindowBuildMethods.cs +++ b/Editor/Mono/BuildPlayerWindowBuildMethods.cs @@ -14,6 +14,7 @@ using UnityEditor.Connect; using UnityEditor.Profiling; using UnityEditor.Utils; +using UnityEditor.Build.Profile; namespace UnityEditor { @@ -230,53 +231,15 @@ internal static BuildPlayerOptions GetBuildPlayerOptionsInternal(bool askForBuil BuildTargetGroup buildTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup; int subtarget = EditorUserBuildSettings.GetSelectedSubtargetFor(buildTarget); - // Pick location for the build - string newLocation = ""; + options.options = BuildProfileModuleUtil.GetBuildOptions(buildTarget, buildTargetGroup, string.Empty, options.options); - //Check if Lz4 is supported for the current buildtargetgroup and enable it if need be - if (PostprocessBuildPlayer.SupportsLz4Compression(buildTarget)) - { - var compression = EditorUserBuildSettings.GetCompressionType(buildTargetGroup); - if (compression < 0) - compression = PostprocessBuildPlayer.GetDefaultCompression(buildTarget); - if (compression == Compression.Lz4) - options.options |= BuildOptions.CompressWithLz4; - else if (compression == Compression.Lz4HC) - options.options |= BuildOptions.CompressWithLz4HC; - } - - bool developmentBuild = EditorUserBuildSettings.development; - if (developmentBuild) - options.options |= BuildOptions.Development; - if (EditorUserBuildSettings.allowDebugging && developmentBuild) - options.options |= BuildOptions.AllowDebugging; - if (EditorUserBuildSettings.symlinkSources) - options.options |= BuildOptions.SymlinkSources; - - if(BuildTargetDiscovery.TryGetBuildTarget(buildTarget, out IBuildTarget iBuildTarget)) - { - if (EditorUserBuildSettings.connectProfiler && (developmentBuild || (iBuildTarget.PlayerConnectionPlatformProperties?.ForceAllowProfilerConnection ?? false)) ) - options.options |= BuildOptions.ConnectWithProfiler; - } - - if (EditorUserBuildSettings.buildWithDeepProfilingSupport && developmentBuild) - options.options |= BuildOptions.EnableDeepProfilingSupport; - if (EditorUserBuildSettings.buildScriptsOnly) - options.options |= BuildOptions.BuildScriptsOnly; - if (!string.IsNullOrEmpty(ProfilerUserSettings.customConnectionID) && developmentBuild) - options.options |= BuildOptions.CustomConnectionID; - - - if (IsInstallInBuildFolderOption()) - { - options.options |= BuildOptions.InstallInBuildFolder; - } - else if ((options.options & BuildOptions.PatchPackage) == 0) + if ((options.options & BuildOptions.InstallInBuildFolder) == 0 && + (options.options & BuildOptions.PatchPackage) == 0) { if (askForBuildLocation && !PickBuildLocation(buildTargetGroup, buildTarget, subtarget, options.options, out updateExistingBuild)) throw new BuildMethodException(); - newLocation = EditorUserBuildSettings.GetBuildLocation(buildTarget); + var newLocation = EditorUserBuildSettings.GetBuildLocation(buildTarget); if (newLocation.Length == 0) { diff --git a/Editor/Mono/BuildProfile/BuildProfile.cs b/Editor/Mono/BuildProfile/BuildProfile.cs index 8dee9d232e..9511ff5583 100644 --- a/Editor/Mono/BuildProfile/BuildProfile.cs +++ b/Editor/Mono/BuildProfile/BuildProfile.cs @@ -3,10 +3,12 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; +using System.Collections.Generic; using System.Runtime.InteropServices; using UnityEngine; using UnityEngine.Bindings; using UnityEngine.Scripting; +using UnityEditor.Modules; namespace UnityEditor.Build.Profile { @@ -44,7 +46,7 @@ internal StandaloneBuildSubtarget subtarget /// /// Module name used to fetch build profiles. /// - [SerializeField] string m_ModuleName; + string m_ModuleName; [VisibleToOtherModules] internal string moduleName { @@ -52,6 +54,18 @@ internal string moduleName set => m_ModuleName = value; } + /// + /// Platform ID of the build profile. + /// Correspond to platform GUID in + /// + [SerializeField] string m_PlatformId; + [VisibleToOtherModules] + internal string platformId + { + get => m_PlatformId; + set => m_PlatformId = value; + } + /// /// Platform module specific build settings; e.g. AndroidBuildSettings. /// @@ -63,9 +77,11 @@ internal BuildProfilePlatformSettingsBase platformBuildProfile set => m_PlatformBuildProfile = value; } + /// + /// List of scenes specified in the build profile. + /// [SerializeField] private EditorBuildSettingsScene[] m_Scenes = Array.Empty(); - [VisibleToOtherModules] - internal EditorBuildSettingsScene[] scenes + public EditorBuildSettingsScene[] scenes { get { @@ -85,6 +101,38 @@ internal EditorBuildSettingsScene[] scenes } } + /// + /// Scripting Compilation Defines used during player and editor builds. + /// + /// + /// fetches active profile + /// define be deserializing the YAML file and assumes defines will be found under "m_ScriptingDefines" node. + /// + [SerializeField] private string[] m_ScriptingDefines = Array.Empty(); + public string[] scriptingDefines + { + get => m_ScriptingDefines; + set => m_ScriptingDefines = value; + } + + [SerializeField] + PlayerSettingsYaml m_PlayerSettingsYaml = new(); + + PlayerSettings m_PlayerSettings; + [VisibleToOtherModules] + internal PlayerSettings playerSettings + { + get { return m_PlayerSettings; } + + set { m_PlayerSettings = value; } + } + + // TODO: Return server IBuildTargets for server build profiles. (https://jira.unity3d.com/browse/PLAT-6612) + /// + /// Get the IBuildTarget of the build profile. + /// + internal IBuildTarget GetIBuildTarget() => ModuleManager.GetIBuildTarget(buildTarget); + /// /// Returns true if the given is the active profile or a classic /// profile for the EditorUserBuildSettings active build target. @@ -99,12 +147,9 @@ internal bool IsActiveBuildProfileOrPlatform() || !BuildProfileContext.IsClassicPlatformProfile(this)) return false; - if (!BuildProfileModuleUtil.IsStandalonePlatform(buildTarget)) - return buildTarget == EditorUserBuildSettings.activeBuildTarget; - - var profileModuleName = BuildProfileModuleUtil.GetModuleName(buildTarget); - var activeModuleName = BuildProfileModuleUtil.GetModuleName(EditorUserBuildSettings.activeBuildTarget); - return profileModuleName == activeModuleName && subtarget == EditorUserBuildSettings.standaloneBuildSubtarget; + var activePlatformId = BuildProfileModuleUtil.GetPlatformId( + EditorUserBuildSettings.activeBuildTarget, EditorUserBuildSettings.standaloneBuildSubtarget); + return platformId == activePlatformId; } [VisibleToOtherModules] @@ -112,18 +157,85 @@ internal bool CanBuildLocally() { // Note: A platform build profile may have a non-null value even if its module is not installed. // This scenario is true for server platform profiles, which are the same type as the standalone one. - return platformBuildProfile != null && BuildProfileModuleUtil.IsModuleInstalled(moduleName, subtarget); + return platformBuildProfile != null && BuildProfileModuleUtil.IsModuleInstalled(platformId); + } + + internal string GetLastRunnableBuildPathKey() + { + if (platformBuildProfile == null) + return string.Empty; + + var key = platformBuildProfile.GetLastRunnableBuildPathKey(); + if (string.IsNullOrEmpty(key) || BuildProfileContext.IsClassicPlatformProfile(this)) + return key; + + string assetPath = AssetDatabase.GetAssetPath(this); + return BuildProfileModuleUtil.GetLastRunnableBuildKeyFromAssetPath(assetPath, key); } void OnEnable() { + ValidateDataConsistency(); + + moduleName = BuildProfileModuleUtil.GetModuleName(platformId); + // Check if the platform support module has been installed, // and try to set an uninitialized platform settings. if (platformBuildProfile == null) TryCreatePlatformSettings(); - CheckSceneListConsistency(); onBuildProfileEnable?.Invoke(this); + LoadPlayerSettings(); + + if (!EditorUserBuildSettings.isBuildProfileAvailable + || BuildProfileContext.instance.activeProfile != this) + return; + + // On disk changes invoke OnEnable, + // Check against the last observed editor defines. + string[] lastCompiledDefines = BuildProfileContext.instance.cachedEditorScriptingDefines; + if (ArrayUtility.ArrayEquals(m_ScriptingDefines, lastCompiledDefines)) + { + return; + } + BuildProfileContext.instance.cachedEditorScriptingDefines = m_ScriptingDefines; + BuildProfileModuleUtil.RequestScriptCompilation(this); + } + + void OnDisable() + { + RemovePlayerSettings(); + + // Active profile YAML may be read from disk during startup or + // Asset Database refresh, flush pending changes to disk. + if (BuildProfileContext.instance.activeProfile != this) + return; + + AssetDatabase.SaveAssetIfDirty(this); + } + + void ValidateDataConsistency() + { + // TODO: Remove migration code (https://jira.unity3d.com/browse/PLAT-8909) + // Set platform ID for build profiles created before it is introduced. + if (string.IsNullOrEmpty(platformId)) + { + platformId = BuildProfileContext.IsSharedProfile(buildTarget) ? + new GUID(string.Empty).ToString() : BuildProfileModuleUtil.GetPlatformId(buildTarget, subtarget); + EditorUtility.SetDirty(this); + } + else + { + var (curBuildTarget, curSubtarget) = BuildProfileModuleUtil.GetBuildTargetAndSubtarget(platformId); + if (buildTarget != curBuildTarget || subtarget != curSubtarget) + { + buildTarget = curBuildTarget; + subtarget = curSubtarget; + EditorUtility.SetDirty(this); + } + } + + CheckSceneListConsistency(); } /// diff --git a/Editor/Mono/BuildProfile/BuildProfileAPI.cs b/Editor/Mono/BuildProfile/BuildProfileAPI.cs index 09dbe84772..19640e99c8 100644 --- a/Editor/Mono/BuildProfile/BuildProfileAPI.cs +++ b/Editor/Mono/BuildProfile/BuildProfileAPI.cs @@ -27,6 +27,11 @@ public static BuildProfile GetActiveBuildProfile() public static void SetActiveBuildProfile(BuildProfile buildProfile) { BuildProfileContext.instance.activeProfile = buildProfile; + + if (buildProfile == null) + return; + + BuildProfileModuleUtil.SwitchLegacyActiveFromBuildProfile(buildProfile); } } } diff --git a/Editor/Mono/BuildProfile/BuildProfileCLI.cs b/Editor/Mono/BuildProfile/BuildProfileCLI.cs index 3a30465568..0acea93770 100644 --- a/Editor/Mono/BuildProfile/BuildProfileCLI.cs +++ b/Editor/Mono/BuildProfile/BuildProfileCLI.cs @@ -10,12 +10,15 @@ namespace UnityEditor.Build.Profile internal static class BuildProfileCLI { [RequiredByNativeCode] - internal static void SetActiveBuildProfileFromPath(string buildProfilePath) + internal static bool SetActiveBuildProfileFromPath(string buildProfilePath) { if (LoadFromPath(buildProfilePath, out BuildProfile buildProfile)) { BuildProfileContext.instance.activeProfile = buildProfile; + return true; } + + return false; } static bool LoadFromPath(string buildProfilePath, out BuildProfile buildProfile) @@ -32,5 +35,18 @@ static bool LoadFromPath(string buildProfilePath, out BuildProfile buildProfile) return buildProfile != null; } + + [RequiredByNativeCode] + static void BuildActiveProfileWithPath(string locationPathName) + { + var options = new BuildPlayerWithProfileOptions() + { + buildProfile = BuildProfile.GetActiveBuildProfile(), + locationPathName = locationPathName, + options = BuildOptions.None + }; + + BuildPipeline.BuildPlayer(options); + } } } diff --git a/Editor/Mono/BuildProfile/BuildProfileContext.cs b/Editor/Mono/BuildProfile/BuildProfileContext.cs index 2576550357..32f1aa9e87 100644 --- a/Editor/Mono/BuildProfile/BuildProfileContext.cs +++ b/Editor/Mono/BuildProfile/BuildProfileContext.cs @@ -31,10 +31,29 @@ internal sealed class BuildProfileContext : ScriptableObject [SerializeField] BuildProfile m_ActiveProfile; + [SerializeField] + string[] m_CachedEditorScriptingDefines = Array.Empty(); + + [SerializeField] + List m_LastRunnableBuildPathKeys = new(); + internal List LastRunnableBuildPathKeys => m_LastRunnableBuildPathKeys; + /// - /// Cached mapping of module name to classic platform build profile. + /// Cached mapping of platform ID to classic platform build profile. /// - Dictionary<(string, StandaloneBuildSubtarget), BuildProfile> m_BuildModuleNameToClassicPlatformProfile = new(); + Dictionary m_PlatformIdToClassicPlatformProfile = new(); + + /// + /// Cached editor scripting defines for the active profile. + /// On disk changes to build profile asset, cached value is referenced + /// when determining if a recompilation is required. + /// + [VisibleToOtherModules] + internal string[] cachedEditorScriptingDefines + { + get => m_CachedEditorScriptingDefines; + set => m_CachedEditorScriptingDefines = value; + } /// /// Specifies the custom build profile used by the build pipeline and editor APIs when getting build settings. @@ -65,14 +84,17 @@ internal BuildProfile activeProfile var prev = m_ActiveProfile; if (value == null || value.platformBuildProfile == null) { + m_ActiveProfile.UpdateGlobalManagerPlayerSettings(activeWillBeRemoved: true); m_ActiveProfile = null; Save(); + EditorUserBuildSettings.SetBuildProfilePath(string.Empty); activeProfileChanged?.Invoke(prev, m_ActiveProfile); + BuildProfileModuleUtil.RequestScriptCompilation(null); return; } - if (m_BuildModuleNameToClassicPlatformProfile.TryGetValue( - (value.moduleName, value.subtarget), out var entry) && entry == value) + if (m_PlatformIdToClassicPlatformProfile.TryGetValue( + value.platformId, out var entry) && entry == value) { Debug.LogWarning("[BuildProfile] Classic Platforms cannot be set as the active build profile."); return; @@ -80,7 +102,23 @@ internal BuildProfile activeProfile m_ActiveProfile = value; Save(); + EditorUserBuildSettings.SetBuildProfilePath(AssetDatabase.GetAssetPath(m_ActiveProfile)); activeProfileChanged?.Invoke(prev, m_ActiveProfile); + m_ActiveProfile.UpdateGlobalManagerPlayerSettings(); + BuildProfileModuleUtil.RequestScriptCompilation(m_ActiveProfile); + } + } + + internal static void HandlePendingChangesBeforeEnterPlaymode() + { + if (!EditorUserBuildSettings.isBuildProfileAvailable) + return; + + var defines = BuildDefines.GetBuildProfileScriptDefines(); + if (!ArrayUtility.ArrayEquals(defines, instance.cachedEditorScriptingDefines)) + { + instance.cachedEditorScriptingDefines = defines; + PlayerSettings.RecompileScripts("Build profile has been modified."); } } @@ -138,7 +176,7 @@ static BuildProfileContext() // We delay the creation of the classic platform profiles until the next editor update. EditorApplication.delayCall += () => { - if(s_Instance == null) + if (s_Instance == null) CreateOrLoad(); }; } @@ -148,7 +186,7 @@ private BuildProfileContext() { if (s_Instance != null) { - Debug.LogError("BuildProfileProvider singleton already exists."); + Debug.LogError("BuildProfileContext singleton already exists."); } else { @@ -186,22 +224,21 @@ internal static bool TryGetActiveOrClassicPlatformSettingsBase( return false; } - internal BuildProfile GetForClassicPlatform(BuildTarget target, StandaloneBuildSubtarget subTarget) + internal BuildProfile GetForClassicPlatform(BuildTarget target, StandaloneBuildSubtarget subtarget) { if (!BuildProfileModuleUtil.IsStandalonePlatform(target)) - subTarget = StandaloneBuildSubtarget.Default; - else if (subTarget == StandaloneBuildSubtarget.Default) - subTarget = StandaloneBuildSubtarget.Player; + subtarget = StandaloneBuildSubtarget.Default; + else if (subtarget == StandaloneBuildSubtarget.Default) + subtarget = StandaloneBuildSubtarget.Player; - var key = GetKey(target, subTarget); - return m_BuildModuleNameToClassicPlatformProfile.GetValueOrDefault(key); + var platformId = BuildProfileModuleUtil.GetPlatformId(target, subtarget); + return m_PlatformIdToClassicPlatformProfile.GetValueOrDefault(platformId); } [VisibleToOtherModules("UnityEditor.BuildProfileModule")] internal static bool IsClassicPlatformProfile(BuildProfile profile) { - var key = (profile.moduleName, profile.subtarget); - if (instance.m_BuildModuleNameToClassicPlatformProfile.TryGetValue(key, out var classicProfile)) + if (instance.m_PlatformIdToClassicPlatformProfile.TryGetValue(profile.platformId, out var classicProfile)) { return classicProfile == profile; } @@ -215,32 +252,33 @@ internal static bool IsClassicPlatformProfile(BuildProfile profile) /// /// [VisibleToOtherModules("UnityEditor.BuildProfileModule")] - internal List<(string, StandaloneBuildSubtarget)> GetMissingKnownPlatformModules() + internal List GetMissingKnownPlatformModules() { - var result = new List<(string, StandaloneBuildSubtarget)>(); + var missingPlatforms = new List(); var keys = BuildProfileModuleUtil.FindAllViewablePlatforms(); for (var index = 0; index < keys.Count; index++) { var key = keys[index]; - if (m_BuildModuleNameToClassicPlatformProfile.ContainsKey(key)) + if (m_PlatformIdToClassicPlatformProfile.ContainsKey(key)) continue; // Installed flag, as calculated by BuildPlatform - if (BuildProfileModuleUtil.IsModuleInstalled(key.Item1, key.Item2)) + if (BuildProfileModuleUtil.IsModuleInstalled(key)) continue; // Some build targets are only compatible with specific OS, // from BuildPlayerWindow.ActiveBuildTargetsGUI() - var iBuildTarget = ModuleManager.GetIBuildTarget(key.Item1); + var buildTarget = BuildProfileModuleUtil.GetBuildTargetAndSubtarget(key).Item1; + var iBuildTarget = ModuleManager.GetIBuildTarget(buildTarget); if (iBuildTarget != null && !(iBuildTarget.BuildPlatformProperties?.CanBuildOnCurrentHostPlatform ?? true)) continue; - result.Add(key); + missingPlatforms.Add(key); } - return result; + return missingPlatforms; } /// @@ -274,9 +312,11 @@ void SyncActiveProfileToFallback() void OnDisable() { Save(); + EditorUserBuildSettings.SetBuildProfilePath((m_ActiveProfile != null) ? + AssetDatabase.GetAssetPath(m_ActiveProfile) : string.Empty); // Platform profiles must be manually serialized for changes to persist. - foreach (var kvp in m_BuildModuleNameToClassicPlatformProfile) + foreach (var kvp in m_PlatformIdToClassicPlatformProfile) { SaveBuildProfileInProject(kvp.Value); } @@ -307,7 +347,7 @@ void OnEnable() var key = viewablePlatformKeys[index]; string path = GetFilePathForBuildProfile(key); - if (!File.Exists(path) || !BuildProfileModuleUtil.IsModuleInstalled(key.Item1, key.Item2)) + if (!File.Exists(path) || !BuildProfileModuleUtil.IsModuleInstalled(key)) continue; var profile = InternalEditorUtility.LoadSerializedFileAndForget(path); @@ -317,7 +357,7 @@ void OnEnable() continue; } - m_BuildModuleNameToClassicPlatformProfile.Add((profileObj.moduleName, profileObj.subtarget), profileObj); + m_PlatformIdToClassicPlatformProfile.Add(profileObj.platformId, profileObj); classicPlatformProfiles.Add(profileObj); } @@ -359,10 +399,9 @@ void CheckInstalledBuildPlatforms() for (var index = 0; index < viewablePlatformKeys.Count; index++) { var key = viewablePlatformKeys[index]; - var moduleName = key.Item1; - var subtarget = key.Item2; + var moduleName = BuildProfileModuleUtil.GetModuleName(key); - if (!BuildProfileModuleUtil.IsModuleInstalled(moduleName, subtarget)) + if (!BuildProfileModuleUtil.IsModuleInstalled(key)) continue; if (ModuleManager.GetBuildProfileExtension(moduleName) == null) @@ -373,27 +412,30 @@ void CheckInstalledBuildPlatforms() continue; } - var buildTarget = BuildProfileModuleUtil.GetBuildTarget(moduleName); - GetOrCreateClassicPlatformBuildProfile(buildTarget, subtarget); + GetOrCreateClassicPlatformBuildProfile(key); } GetOrCreateSharedBuildProfile(); } - BuildProfile GetOrCreateClassicPlatformBuildProfile(BuildTarget target, StandaloneBuildSubtarget subTarget) + BuildProfile GetOrCreateClassicPlatformBuildProfile(string platformId) { - var key = GetKey(target, subTarget); - if (m_BuildModuleNameToClassicPlatformProfile.TryGetValue(key, out var profile) && profile != null) + if (m_PlatformIdToClassicPlatformProfile.TryGetValue(platformId, out var profile) && profile != null) { return profile; } + // Migrate legacy build target indexed profiles to platform ID indexed profiles. + var migratedProfile = MigrateLegacyIndexedClassicPlatformProfile(platformId); + if (migratedProfile != null) + return migratedProfile; + // Platform profiles are not managed by the AssetDatabase. // We will manually handle serialization and deserialization of these objects. - var buildProfile = BuildProfile.CreateInstance(target, subTarget); + var buildProfile = BuildProfile.CreateInstance(new GUID(platformId)); buildProfile.hideFlags = HideFlags.DontSave; - m_BuildModuleNameToClassicPlatformProfile.Add(key, buildProfile); + m_PlatformIdToClassicPlatformProfile.Add(platformId, buildProfile); classicPlatformProfiles.Add(buildProfile); // Only copy after adding to the build target -> classic profiles dictionary, so EditorUserBuildSettings @@ -434,7 +476,7 @@ BuildProfile GetOrCreateSharedBuildProfile() var buildProfile = ScriptableObject.CreateInstance(); buildProfile.buildTarget = BuildTarget.NoTarget; buildProfile.subtarget = StandaloneBuildSubtarget.Default; - buildProfile.moduleName = string.Empty; + buildProfile.platformId = new GUID(string.Empty).ToString(); buildProfile.platformBuildProfile = new SharedPlatformSettings(); buildProfile.hideFlags = HideFlags.DontSave; @@ -449,7 +491,34 @@ BuildProfile GetOrCreateSharedBuildProfile() return buildProfile; } - static (string, StandaloneBuildSubtarget) GetKey(BuildTarget buildTarget, StandaloneBuildSubtarget subtarget) + // TODO: Remove migration code (https://jira.unity3d.com/browse/PLAT-8909) + BuildProfile MigrateLegacyIndexedClassicPlatformProfile(string platformId) + { + var (buildTarget, subtarget) = BuildProfileModuleUtil.GetBuildTargetAndSubtarget(platformId); + var legacyKey = GetLegacyKey(buildTarget, subtarget); + var legacyPath = GetLegacyFilePathForBuildProfile(legacyKey); + + if (!File.Exists(legacyPath)) + return null; + + var profileObj = InternalEditorUtility.LoadSerializedFileAndForget(legacyPath); + if (profileObj == null || profileObj.Length == 0 || profileObj[0] is not BuildProfile profile) + { + Debug.LogWarning($"Failed to load build profile from {legacyPath}."); + return null; + } + + profile.platformId = platformId; + m_PlatformIdToClassicPlatformProfile.Add(profile.platformId, profile); + classicPlatformProfiles.Add(profile); + + SaveBuildProfileInProject(profile); + File.Delete(legacyPath); + + return profile; + } + + static (string, StandaloneBuildSubtarget) GetLegacyKey(BuildTarget buildTarget, StandaloneBuildSubtarget subtarget) { if (buildTarget == BuildTarget.NoTarget) { @@ -466,12 +535,13 @@ static void SaveBuildProfileInProject(BuildProfile profile) Directory.CreateDirectory(k_BuildProfilePath); } - string path = IsSharedProfile(profile.buildTarget) ? k_SharedProfilePath : GetFilePathForBuildProfile((profile.moduleName, profile.subtarget)); + string path = IsSharedProfile(profile.buildTarget) ? k_SharedProfilePath : GetFilePathForBuildProfile(profile.platformId); InternalEditorUtility.SaveToSerializedFileAndForget(new []{ profile }, path, allowTextSerialization: true); } static void CreateOrLoad() { + // LoadSerializedFileAndForget will call non-static BuildProfileContext constructor var buildProfileContext = InternalEditorUtility.LoadSerializedFileAndForget(k_BuildProfileProviderAssetPath); if (buildProfileContext != null && buildProfileContext.Length > 0 && buildProfileContext[0] != null) { @@ -479,7 +549,7 @@ static void CreateOrLoad() if (s_Instance == null) Debug.LogError("BuildProfileContext asset exists but could not be loaded."); } - else + else if (s_Instance == null) { s_Instance = CreateInstance(); s_Instance.hideFlags = HideFlags.DontSave; @@ -488,6 +558,12 @@ static void CreateOrLoad() System.Diagnostics.Debug.Assert(s_Instance != null); s_Instance.CheckInstalledBuildPlatforms(); + + EditorUserBuildSettings.SetBuildProfilePath((s_Instance.m_ActiveProfile != null) ? + AssetDatabase.GetAssetPath(s_Instance.m_ActiveProfile) : string.Empty); + s_Instance.cachedEditorScriptingDefines = BuildDefines.GetBuildProfileScriptDefines(); + + BuildProfileModuleUtil.DeleteLastRunnableBuildKeyForDeletedProfiles(); } [RequiredByNativeCode, UsedImplicitly] @@ -534,17 +610,26 @@ static string GetActiveOrClassicProfileRawPlatformSetting(string settingName, Bu return string.Empty; } + [RequiredByNativeCode] + static string GetActiveBuildProfilePath() + { + if (instance.activeProfile) + return AssetDatabase.GetAssetPath(instance.activeProfile); + + return string.Empty; + } + static bool ShouldReturnActiveProfile(BuildTarget buildTarget, StandaloneBuildSubtarget subtarget, string sharedSetting = null) { if (!string.IsNullOrEmpty(sharedSetting)) return IsSharedSettingEnabledInActiveProfile(sharedSetting); var activeProfile = instance.activeProfile; - if (activeProfile == null || buildTarget == BuildTarget.NoTarget || subtarget != activeProfile.subtarget) + if (activeProfile == null || buildTarget == BuildTarget.NoTarget) return false; - var targetModuleName = ModuleManager.GetTargetStringFrom(buildTarget); - return targetModuleName == activeProfile.moduleName; + var platformId = BuildProfileModuleUtil.GetPlatformId(buildTarget, subtarget); + return platformId == activeProfile.platformId; } static bool IsSharedSettingEnabledInActiveProfile(string settingName) @@ -560,12 +645,15 @@ static bool IsSharedSettingEnabledInActiveProfile(string settingName) return platformSettingsBase.IsSharedSettingEnabled(settingName); } - static string GetFilePathForBuildProfile((string moduleName, StandaloneBuildSubtarget subtarget) key) => + static string GetFilePathForBuildProfile(string platformId) => + $"{k_BuildProfilePath}/PlatformProfile.{platformId}.asset"; + + static string GetLegacyFilePathForBuildProfile((string moduleName, StandaloneBuildSubtarget subtarget) key) => $"{k_BuildProfilePath}/PlatformProfile.{key.moduleName}.{key.subtarget}.asset"; static void Save() => InternalEditorUtility.SaveToSerializedFileAndForget(new[] { instance }, k_BuildProfileProviderAssetPath, true); - static bool IsSharedProfile(BuildTarget target) => target == BuildTarget.NoTarget; + internal static bool IsSharedProfile(BuildTarget target) => target == BuildTarget.NoTarget; } } diff --git a/Editor/Mono/BuildProfile/BuildProfileCreate.cs b/Editor/Mono/BuildProfile/BuildProfileCreate.cs index f8d18b0db0..d0c4400195 100644 --- a/Editor/Mono/BuildProfile/BuildProfileCreate.cs +++ b/Editor/Mono/BuildProfile/BuildProfileCreate.cs @@ -25,7 +25,20 @@ internal static BuildProfile CreateInstance(BuildTarget buildTarget, StandaloneB var buildProfile = CreateInstance(); buildProfile.buildTarget = buildTarget; buildProfile.subtarget = subtarget; - buildProfile.moduleName = moduleName; + buildProfile.platformId = BuildProfileModuleUtil.GetPlatformId(buildTarget, subtarget); + buildProfile.OnEnable(); + return buildProfile; + } + + internal static BuildProfile CreateInstance(GUID platformGuid) + { + var platformId = platformGuid.ToString(); + var (buildTarget, subtarget) = BuildProfileModuleUtil.GetBuildTargetAndSubtarget(platformId); + var moduleName = BuildProfileModuleUtil.GetModuleName(buildTarget); + var buildProfile = CreateInstance(); + buildProfile.buildTarget = buildTarget; + buildProfile.subtarget = subtarget; + buildProfile.platformId = platformId; buildProfile.OnEnable(); return buildProfile; } @@ -35,12 +48,14 @@ internal static BuildProfile CreateInstance(BuildTarget buildTarget, StandaloneB /// event after an asset is created by AssetDatabase.CreateAsset. /// [VisibleToOtherModules("UnityEditor.BuildProfileModule")] - internal static void CreateInstance(string moduleName, StandaloneBuildSubtarget subtarget, string assetPath) + internal static void CreateInstance(string platformId, string assetPath) { + var (buildTarget, subtarget) = BuildProfileModuleUtil.GetBuildTargetAndSubtarget(platformId); + var moduleName = BuildProfileModuleUtil.GetModuleName(buildTarget); var buildProfile = CreateInstance(); - buildProfile.buildTarget = BuildProfileModuleUtil.GetBuildTarget(moduleName); + buildProfile.buildTarget = buildTarget; buildProfile.subtarget = subtarget; - buildProfile.moduleName = moduleName; + buildProfile.platformId = platformId; AssetDatabase.CreateAsset( buildProfile, AssetDatabase.GenerateUniqueAssetPath(assetPath)); diff --git a/Editor/Mono/BuildProfile/BuildProfileModuleUtil.cs b/Editor/Mono/BuildProfile/BuildProfileModuleUtil.cs index c0a6b884d0..90c7d08d22 100644 --- a/Editor/Mono/BuildProfile/BuildProfileModuleUtil.cs +++ b/Editor/Mono/BuildProfile/BuildProfileModuleUtil.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.Collections.Generic; using UnityEditor.Modules; using UnityEngine; @@ -9,6 +10,7 @@ using UnityEngine.Rendering; using UnityEngine.UIElements; using TargetAttributes = UnityEditor.BuildTargetDiscovery.TargetAttributes; +using UnityEditor.Profiling; namespace UnityEditor.Build.Profile { @@ -21,8 +23,10 @@ internal class BuildProfileModuleUtil const string k_BuyProUrl = "https://store.unity.com/products/unity-pro"; const string k_ConsoleModuleUrl = "https://unity3d.com/platform-installation"; const string k_BuildSettingsPlatformIconFormat = "BuildSettings.{0}"; + const string k_LastRunnableBuildPathSeparator = "_"; static readonly string k_NoModuleLoaded = L10n.Tr("No {0} module loaded."); static readonly string k_EditorWillNeedToBeReloaded = L10n.Tr("Note: Editor will need to be restarted to load any newly installed modules"); + static readonly string k_BuildProfileRecompileReason = L10n.Tr("Active build profile scripting defines changes."); static readonly GUIContent k_OpenDownloadPage = EditorGUIUtility.TrTextContent("Open Download Page"); static readonly GUIContent k_InstallModuleWithHub = EditorGUIUtility.TrTextContent("Install with Unity Hub"); static Dictionary s_DiscoveredTargetInfos = InitializeDiscoveredTargetDict(); @@ -37,8 +41,12 @@ internal class BuildProfileModuleUtil /// value in the old BuildSettings window. /// /// - public static string GetClassicPlatformDisplayName(string moduleName, StandaloneBuildSubtarget subtarget) => - (moduleName, subtarget) switch + public static string GetClassicPlatformDisplayName(string platformId) + { + var (buildTarget, subtarget) = GetBuildTargetAndSubtarget(platformId); + var moduleName = GetModuleName(buildTarget); + + return (moduleName, subtarget) switch { ("OSXStandalone", StandaloneBuildSubtarget.Server) => "Mac Server", ("WindowsStandalone", StandaloneBuildSubtarget.Server) => "Windows Server", @@ -46,29 +54,30 @@ public static string GetClassicPlatformDisplayName(string moduleName, Standalone ("OSXStandalone", _) => "Mac", ("WindowsStandalone", _) => "Windows", ("LinuxStandalone", _) => "Linux", - _ => GetModuleDisplayName(moduleName) + _ => GetModuleDisplayName(moduleName), }; + } /// /// Fetch default editor platform icon texture. /// - public static Texture2D GetPlatformIcon(string moduleName, StandaloneBuildSubtarget subtarget) + public static Texture2D GetPlatformIcon(string platformId) { - if (LoadBuildProfileIcon(moduleName, out Texture2D icon)) + if (LoadBuildProfileIcon(platformId, out Texture2D icon)) return icon; - return EditorGUIUtility.LoadIcon(GetPlatformIconId(moduleName, subtarget)); + return EditorGUIUtility.LoadIcon(GetPlatformIconId(platformId)); } /// /// Fetch small (16x16) editor platform icon texture. /// - public static Texture2D GetPlatformIconSmall(string moduleName, StandaloneBuildSubtarget subtarget) + public static Texture2D GetPlatformIconSmall(string platformId) { - if (LoadBuildProfileIcon(moduleName, out Texture2D icon)) + if (LoadBuildProfileIcon(platformId, out Texture2D icon)) return icon; - return EditorGUIUtility.LoadIcon(GetPlatformIconId(moduleName, subtarget) + ".Small"); + return EditorGUIUtility.LoadIcon(GetPlatformIconId(platformId) + ".Small"); } /// @@ -91,13 +100,15 @@ public static Texture2D GetWarningIcon() /// Returns true if the module is installed and editor has permissions /// for the given build target. /// - public static bool IsModuleInstalled(string moduleName, StandaloneBuildSubtarget subtarget) + public static bool IsModuleInstalled(string platformId) { + var (buildTarget, subtarget) = GetBuildTargetAndSubtarget(platformId); + var moduleName = GetModuleName(buildTarget); + // NamedBuildTarget will be deprecated. This code is extracted from // NamedBuildTarget.FromActiveSettings. Except instead of taking a dependency // on Editor User Build Settings, we use the passed subtarget. NamedBuildTarget namedTarget; - var buildTarget = GetBuildTarget(moduleName); var buildTargetGroup = BuildPipeline.GetBuildTargetGroup(buildTarget); if (buildTargetGroup == BuildTargetGroup.Standalone && subtarget == StandaloneBuildSubtarget.Server) @@ -119,8 +130,9 @@ public static bool IsModuleInstalled(string moduleName, StandaloneBuildSubtarget /// /// Returns true if an installed module supports build profiles. /// - public static bool IsBuildProfileSupported(string moduleName, StandaloneBuildSubtarget subtarget) + public static bool IsBuildProfileSupported(string platformId) { + var moduleName = GetModuleName(platformId); return ModuleManager.GetBuildProfileExtension(moduleName) != null; } @@ -128,13 +140,15 @@ public static bool IsBuildProfileSupported(string moduleName, StandaloneBuildSub /// Generate button and label for downloading a platform module. /// /// - public static VisualElement CreateModuleNotInstalledElement(string moduleName, StandaloneBuildSubtarget subtarget) + public static VisualElement CreateModuleNotInstalledElement(string platformId) { - var buildTarget = GetBuildTarget(moduleName); + var (buildTarget, subtarget) = GetBuildTargetAndSubtarget(platformId); + var moduleName = GetModuleName(buildTarget); var targetGroup = BuildPipeline.GetBuildTargetGroup(buildTarget); var namedBuildTarget = (subtarget == StandaloneBuildSubtarget.Server) ? NamedBuildTarget.Server : NamedBuildTarget.FromBuildTargetGroup(targetGroup); + if (namedBuildTarget == NamedBuildTarget.Server) moduleName = moduleName.Replace("Standalone", "DedicatedServer"); @@ -148,9 +162,9 @@ public static VisualElement CreateModuleNotInstalledElement(string moduleName, S /// BuildTarget. /// /// null when no license errors, else license check UI - public static VisualElement CreateLicenseNotFoundElement(string moduleName) + public static VisualElement CreateLicenseNotFoundElement(string platformId) { - var buildTarget = GetBuildTarget(moduleName); + var buildTarget = GetBuildTargetAndSubtarget(platformId).Item1; if (BuildPipeline.LicenseCheck(buildTarget)) return null; @@ -194,6 +208,12 @@ public static string GetModuleName(BuildTarget buildTarget) return BuildTargetDiscovery.GetModuleNameForBuildTarget(buildTarget); } + public static string GetModuleName(string platformId) + { + var buildTarget = GetBuildTargetAndSubtarget(platformId).Item1; + return GetModuleName(buildTarget); + } + /// /// Internal method for switching active build target and subtarget. /// @@ -231,27 +251,104 @@ public static void CallInternalBuildMethods(bool askForBuildLocation, BuildOptio BuildPlayerWindow.CallBuildMethods(askForBuildLocation, options); } - public static IBuildProfileExtension GetBuildProfileExtension(BuildTarget buildTarget) => - ModuleManager.GetBuildProfileExtension(ModuleManager.GetTargetStringFromBuildTarget(buildTarget)); + /// + /// Construct the build player options from the active build profile. + /// + /// The path where the application will be built. + /// The path to the asset bundle manifest file. + /// Custom build options to be applied. + /// + internal static BuildPlayerOptions GetBuildPlayerOptionsFromActiveProfile(string buildLocation, string assetBundleManifestPath, BuildOptions customBuildOptions) + { + var options = new BuildPlayerOptions(); + var activeProfile = BuildProfile.GetActiveBuildProfile(); + + if (activeProfile == null) + throw new ArgumentException("Active build profile is null."); + + BuildTarget buildTarget = activeProfile.buildTarget; + BuildTargetGroup buildTargetGroup = BuildPipeline.GetBuildTargetGroup(buildTarget); + int subtarget = EditorUserBuildSettings.GetActiveSubtargetFor(buildTarget); + + options.options = GetBuildOptions(buildTarget, buildTargetGroup, buildLocation, customBuildOptions); + options.target = buildTarget; + options.subtarget = subtarget; + options.targetGroup = buildTargetGroup; + options.locationPathName = buildLocation; + options.assetBundleManifestPath = assetBundleManifestPath ?? PostprocessBuildPlayer.GetStreamingAssetsBundleManifestPath(); + options.scenes = EditorBuildSettingsScene.GetActiveSceneList(activeProfile.scenes); + + return options; + } + + internal static BuildOptions GetBuildOptions(BuildTarget buildTarget, BuildTargetGroup buildTargetGroup, string buildLocation, BuildOptions options = BuildOptions.None) + { + // Check if Lz4 is supported for the current buildtargetgroup and enable it if need be + if (PostprocessBuildPlayer.SupportsLz4Compression(buildTarget)) + { + var compression = EditorUserBuildSettings.GetCompressionType(buildTargetGroup); + if (compression < 0) + compression = PostprocessBuildPlayer.GetDefaultCompression(buildTarget); + if (compression == Compression.Lz4) + options |= BuildOptions.CompressWithLz4; + else if (compression == Compression.Lz4HC) + options |= BuildOptions.CompressWithLz4HC; + } + + bool developmentBuild = EditorUserBuildSettings.development; + if (developmentBuild) + options |= BuildOptions.Development; + if (EditorUserBuildSettings.allowDebugging && developmentBuild) + options |= BuildOptions.AllowDebugging; + if (EditorUserBuildSettings.symlinkSources) + options |= BuildOptions.SymlinkSources; + + if (BuildTargetDiscovery.TryGetBuildTarget(buildTarget, out IBuildTarget iBuildTarget)) + { + if (EditorUserBuildSettings.connectProfiler && (developmentBuild || (iBuildTarget.PlayerConnectionPlatformProperties?.ForceAllowProfilerConnection ?? false)) ) + options |= BuildOptions.ConnectWithProfiler; + } + + if (EditorUserBuildSettings.buildWithDeepProfilingSupport && developmentBuild) + options |= BuildOptions.EnableDeepProfilingSupport; + if (EditorUserBuildSettings.buildScriptsOnly) + options |= BuildOptions.BuildScriptsOnly; + if (!string.IsNullOrEmpty(ProfilerUserSettings.customConnectionID) && developmentBuild) + options |= BuildOptions.CustomConnectionID; + + if (EditorUserBuildSettings.installInBuildFolder && + PostprocessBuildPlayer.SupportsInstallInBuildFolder(buildTarget) && + Unsupported.IsSourceBuild()) + { + options |= BuildOptions.InstallInBuildFolder; + } + else if ((options & BuildOptions.PatchPackage) == 0) + { + if (!string.IsNullOrEmpty(buildLocation) && BuildPipeline.BuildCanBeAppended(buildTarget, buildLocation) == CanAppendBuild.Yes) + options |= BuildOptions.AcceptExternalModificationsToPlayer; + } + + return options; + } + + public static IBuildProfileExtension GetBuildProfileExtension(string moduleName) => + ModuleManager.GetBuildProfileExtension(moduleName); public static GUIStyle dropDownToggleButton => EditorStyles.dropDownToggleButton; /// /// Returns all discovered platform keys that are possible Build Profile targets. /// - public static List<(string, StandaloneBuildSubtarget)> FindAllViewablePlatforms() + public static List FindAllViewablePlatforms() { - string windows = ModuleManager.GetTargetStringFrom(BuildTarget.StandaloneWindows64); - string osx = ModuleManager.GetTargetStringFrom(BuildTarget.StandaloneOSX); - string linux = ModuleManager.GetTargetStringFrom(BuildTarget.StandaloneLinux64); - var result = new List<(string, StandaloneBuildSubtarget)>() + var result = new List() { - (windows, StandaloneBuildSubtarget.Player), - (osx, StandaloneBuildSubtarget.Player), - (linux, StandaloneBuildSubtarget.Player), - (windows, StandaloneBuildSubtarget.Server), - (osx, StandaloneBuildSubtarget.Server), - (linux, StandaloneBuildSubtarget.Server) + GetPlatformId(BuildTarget.StandaloneWindows64, StandaloneBuildSubtarget.Player), + GetPlatformId(BuildTarget.StandaloneOSX, StandaloneBuildSubtarget.Player), + GetPlatformId(BuildTarget.StandaloneLinux64, StandaloneBuildSubtarget.Player), + GetPlatformId(BuildTarget.StandaloneWindows64, StandaloneBuildSubtarget.Server), + GetPlatformId(BuildTarget.StandaloneOSX, StandaloneBuildSubtarget.Server), + GetPlatformId(BuildTarget.StandaloneLinux64, StandaloneBuildSubtarget.Server) }; // Swap current editor standalone platform to the top. @@ -270,9 +367,8 @@ public static IBuildProfileExtension GetBuildProfileExtension(BuildTarget buildT if (!installed && buildTargetInfo.HasFlag(TargetAttributes.HideInUI)) continue; - // buildTargetInfo may be missing module name for some target platforms. - var moduleName = ModuleManager.GetTargetStringFromBuildTarget(buildTargetInfo.buildTargetPlatformVal); - result.Add((moduleName, StandaloneBuildSubtarget.Default)); + var platformId = GetPlatformId(buildTargetInfo.buildTargetPlatformVal, StandaloneBuildSubtarget.Default); + result.Add(platformId); } return result; @@ -303,6 +399,55 @@ public static bool IsVirtualTexturingSettingsValid(BuildTarget buildTarget) return supportedAPI; } + /// + /// Remove player settings for deleted build profile assets. For example, when deleting them + /// in the project folder + /// + public static void CleanUpPlayerSettingsForDeletedBuildProfiles(IList currentBuildProfiles) + { + BuildProfile.CleanUpPlayerSettingsForDeletedBuildProfiles(currentBuildProfiles); + } + + /// + /// Check if build profile has serialized player settings + /// + public static bool HasSerializedPlayerSettings(BuildProfile buildProfile) + { + return buildProfile.HasSerializedPlayerSettings(); + } + + /// + /// Serialize build profile player settings + /// + public static void SerializePlayerSettings(BuildProfile buildProfile) + { + buildProfile.SerializePlayerSettings(); + } + + /// + /// Remove build profile player settings object and clear player settings yaml + /// + public static void RemovePlayerSettings(BuildProfile buildProfile) + { + buildProfile.RemovePlayerSettings(clearYaml: true); + } + + /// + /// Create player settings for build profile based on global player settings + /// + public static void CreatePlayerSettingsFromGlobal(BuildProfile buildProfile) + { + buildProfile.CreatePlayerSettingsFromGlobal(); + } + + /// + /// Checks if player settings values are the same as project settings values + /// + public static bool IsDataEqualToProjectSettings(PlayerSettings playerSettings) + { + return BuildProfile.IsDataEqualToProjectSettings(playerSettings); + } + /// Retrieve string of filename invalid characters /// /// @@ -311,9 +456,64 @@ public static string GetFilenameInvalidCharactersStr() return EditorUtility.GetInvalidFilenameChars(); } - internal static BuildTarget GetBuildTarget(string moduleName) + /// + /// Delete last runnable build key in EditorPrefs for a profile that will be deleted + /// + public static void DeleteLastRunnableBuildKeyForProfile(BuildProfile profile) + { + var lastRunnableKey = profile.GetLastRunnableBuildPathKey(); + if (!string.IsNullOrEmpty(lastRunnableKey)) + EditorPrefs.DeleteKey(lastRunnableKey); + } + + /// + /// Delete last runnable build keys in EditorPrefs for deleted profiles + /// + public static void DeleteLastRunnableBuildKeyForDeletedProfiles() + { + List lastRunnableBuildPathKeys = BuildProfileContext.instance.LastRunnableBuildPathKeys; + for (int i = lastRunnableBuildPathKeys.Count - 1; i >= 0; i--) + { + string key = lastRunnableBuildPathKeys[i]; + var assetPath = GetAssetPathFromLastRunnableBuildKey(key); + if (!AssetDatabase.AssetPathExists(assetPath)) + { + lastRunnableBuildPathKeys.RemoveAt(i); + EditorPrefs.DeleteKey(key); + } + } + } + + /// + /// Get last runnable build key from build profile path + /// + public static string GetLastRunnableBuildKeyFromAssetPath(string assetPath, string baseKey) + { + return string.IsNullOrEmpty(assetPath) ? string.Empty : $"{baseKey}{k_LastRunnableBuildPathSeparator}{assetPath}"; + } + + /// On the next editor update recompile scripts. + /// + public static void RequestScriptCompilation(BuildProfile profile) { - return s_DiscoveredTargetInfos[moduleName].buildTargetPlatformVal; + if (profile != null) + BuildProfileContext.instance.cachedEditorScriptingDefines = profile.scriptingDefines; + else + BuildProfileContext.instance.cachedEditorScriptingDefines = Array.Empty(); + + EditorApplication.delayCall += TryRecompileScripts; + } + + /// + /// Recompile scripts if the active build profile scripting defines + /// differs from the last compilation defines. + /// + static void TryRecompileScripts() + { + if (EditorApplication.isCompiling) + return; + + PlayerSettings.RecompileScripts(k_BuildProfileRecompileReason); } [VisibleToOtherModules("UnityEditor.BuildProfileModule")] @@ -322,19 +522,40 @@ internal static void SuppressMissingTypeWarning() SerializationUtility.SuppressMissingTypeWarning(nameof(BuildProfile)); } + internal static string GetBuildProfileLastRunnableBuildPathKey(BuildTarget buildTarget, StandaloneBuildSubtarget standaloneBuildSubtarget) + { + var activeProfile = BuildProfile.GetActiveBuildProfile(); + if (activeProfile != null && activeProfile.buildTarget == buildTarget && activeProfile.subtarget == standaloneBuildSubtarget) + return activeProfile.GetLastRunnableBuildPathKey(); + + var classicProfile = BuildProfileContext.instance.GetForClassicPlatform(buildTarget, standaloneBuildSubtarget); + return classicProfile != null ? classicProfile.GetLastRunnableBuildPathKey() : string.Empty; + } + + internal static void SetBuildProfileLastRunnableBuildPathKey(string key, string value) + { + if (BuildProfile.GetActiveBuildProfile() != null && + !BuildProfileContext.instance.LastRunnableBuildPathKeys.Contains(key)) + { + BuildProfileContext.instance.LastRunnableBuildPathKeys.Add(key); + } + EditorPrefs.SetString(key, value); + } + static Dictionary InitializeDiscoveredTargetDict() { var result = new Dictionary(); foreach (var kvp in BuildTargetDiscovery.GetBuildTargetInfoList()) { - var targetString = ModuleManager.GetTargetStringFromBuildTarget(kvp.buildTargetPlatformVal); + var targetString = GetModuleName(kvp.buildTargetPlatformVal); result.TryAdd(targetString, kvp); } return result; } - static bool LoadBuildProfileIcon(string moduleName, out Texture2D icon) + static bool LoadBuildProfileIcon(string platformId, out Texture2D icon) { + var moduleName = GetModuleName(platformId); if (s_BuildProfileIconModules.Contains(moduleName)) { icon = EditorGUIUtility.FindTexture(typeof(BuildProfile)); @@ -345,8 +566,11 @@ static bool LoadBuildProfileIcon(string moduleName, out Texture2D icon) return false; } - static string GetPlatformIconId(string moduleName, StandaloneBuildSubtarget subtarget) + static string GetPlatformIconId(string platformId) { + var (buildTarget, subtarget) = GetBuildTargetAndSubtarget(platformId); + var moduleName = GetModuleName(buildTarget); + if (subtarget == StandaloneBuildSubtarget.Server) { return string.Format(k_BuildSettingsPlatformIconFormat, "DedicatedServer"); @@ -370,5 +594,27 @@ static string GetModuleDisplayName(string moduleName) return BuildPipeline.GetBuildTargetGroupDisplayName(BuildPipeline.GetBuildTargetGroup(gt.buildTargetPlatformVal)); } + + /// + /// Get build profile path from the last runnable build key + /// + static string GetAssetPathFromLastRunnableBuildKey(string key) + { + int lastUnderscoreIndex = key.LastIndexOf(k_LastRunnableBuildPathSeparator); + return lastUnderscoreIndex != -1 ? key[(lastUnderscoreIndex + 1)..] : string.Empty; + } + + public static string GetPlatformId(BuildTarget buildTarget, StandaloneBuildSubtarget subtarget) + { + var platformGuid = subtarget == StandaloneBuildSubtarget.Server && IsStandalonePlatform(buildTarget) + ? BuildTargetDiscovery.GetGUIDFromBuildTarget(NamedBuildTarget.Server, buildTarget) + : BuildTargetDiscovery.GetGUIDFromBuildTarget(buildTarget); + return platformGuid.ToString(); + } + + public static (BuildTarget, StandaloneBuildSubtarget) GetBuildTargetAndSubtarget(string platformId) + { + return BuildTargetDiscovery.GetBuildTargetAndSubtargetFromGUID(new GUID(platformId)); + } } } diff --git a/Editor/Mono/BuildProfile/BuildProfilePlatformSettingsBase.cs b/Editor/Mono/BuildProfile/BuildProfilePlatformSettingsBase.cs index f8c88b0210..4d4f2f5887 100644 --- a/Editor/Mono/BuildProfile/BuildProfilePlatformSettingsBase.cs +++ b/Editor/Mono/BuildProfile/BuildProfilePlatformSettingsBase.cs @@ -205,5 +205,13 @@ public virtual string GetSharedSetting(string name) { return null; } + + /// + /// Get last path of a runnable build for this build profile + /// + public virtual string GetLastRunnableBuildPathKey() + { + return string.Empty; + } } } diff --git a/Editor/Mono/BuildProfile/BuildProfilePlayerSettings.cs b/Editor/Mono/BuildProfile/BuildProfilePlayerSettings.cs new file mode 100644 index 0000000000..a0905b0f99 --- /dev/null +++ b/Editor/Mono/BuildProfile/BuildProfilePlayerSettings.cs @@ -0,0 +1,205 @@ +// 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; +using UnityEngine; + +namespace UnityEditor.Build.Profile +{ + public partial class BuildProfile + { + [Serializable] + class PlayerSettingsYaml + { + [Serializable] + class YamlSetting + { + public string line; + + public YamlSetting(string newLine) + { + // Prefixing the YAML property value with '|' to escape special characters + // and avoid 'Failed to parse' yaml error + line = $"{"| "}{newLine}"; + } + + public string GetLine() + { + return line[2..]; + } + } + + [SerializeField] + List m_Settings = new(); + + internal void SetSettingsFromYaml(string yamlStr) + { + m_Settings.Clear(); + + // Splitting the YAML single string into individual lines to better readability + // in the asset file + var settings = yamlStr.Split("\n"); + foreach (var setting in settings) + { + var newSetting = new YamlSetting(setting); + m_Settings.Add(newSetting); + } + } + + internal string GetYamlString() + { + var stringBuilder = new StringBuilder(); + foreach (var setting in m_Settings) + { + stringBuilder.AppendLine(setting.GetLine()); + } + return stringBuilder.ToString(); + } + + internal bool HasSettings() + { + return m_Settings.Count > 0; + } + + internal void Clear() + { + m_Settings.Clear(); + } + } + + const string k_ProjectSettingsAssetPath = "ProjectSettings/ProjectSettings.asset"; + + static PlayerSettings s_GlobalPlayerSettings; + + static readonly List s_LoadedPlayerSettings = new(); + + internal void LoadPlayerSettings() + { + TryLoadProjectSettingsAssetPlayerSettings(); + DeserializePlayerSettings(); + } + + internal void CreatePlayerSettingsFromGlobal() + { + if (m_PlayerSettings != null || BuildProfileContext.IsClassicPlatformProfile(this)) + return; + + var newPlayerSettings = Instantiate(s_GlobalPlayerSettings); + + var yamlStr = PlayerSettings.SerializeAsYAMLString(newPlayerSettings); + m_PlayerSettingsYaml.SetSettingsFromYaml(yamlStr); + m_PlayerSettings = newPlayerSettings; + s_LoadedPlayerSettings.Add(m_PlayerSettings); + + UpdateGlobalManagerPlayerSettings(); + } + + internal void RemovePlayerSettings(bool clearYaml = false) + { + if (BuildProfileContext.IsClassicPlatformProfile(this)) + return; + + if (m_PlayerSettings != null) + { + DestroyImmediate(m_PlayerSettings, true); + s_LoadedPlayerSettings.Remove(m_PlayerSettings); + m_PlayerSettings = null; + + if (clearYaml) + m_PlayerSettingsYaml.Clear(); + } + + UpdateGlobalManagerPlayerSettings(activeWillBeRemoved: true); + } + + internal static void CleanUpPlayerSettingsForDeletedBuildProfiles(IList currentBuildProfiles) + { + TrySetProjectSettingsAssetAsGlobalManagerPlayerSettings(); + + for (int i = s_LoadedPlayerSettings.Count - 1; i >= 0; i--) + { + var loadedPlayerSettings = s_LoadedPlayerSettings[i]; + if (loadedPlayerSettings == null) + { + s_LoadedPlayerSettings.RemoveAt(i); + continue; + } + + bool shouldDelete = true; + foreach (var profile in currentBuildProfiles) + { + if (profile.playerSettings == loadedPlayerSettings) + { + shouldDelete = false; + break; + } + } + + if (shouldDelete) + { + s_LoadedPlayerSettings.RemoveAt(i); + DestroyImmediate(loadedPlayerSettings, true); + } + } + } + + internal void SerializePlayerSettings() + { + if (m_PlayerSettings == null) + return; + + var yamlStr = PlayerSettings.SerializeAsYAMLString(m_PlayerSettings); + m_PlayerSettingsYaml.SetSettingsFromYaml(yamlStr); + } + + internal void DeserializePlayerSettings() + { + if (!HasSerializedPlayerSettings()) + return; + + m_PlayerSettings = PlayerSettings.DeserializeFromYAMLString(m_PlayerSettingsYaml.GetYamlString()); + s_LoadedPlayerSettings.Add(m_PlayerSettings); + UpdateGlobalManagerPlayerSettings(); + } + + internal bool HasSerializedPlayerSettings() + { + return m_PlayerSettingsYaml.HasSettings(); + } + + internal void UpdateGlobalManagerPlayerSettings(bool activeWillBeRemoved = false) + { + if (BuildProfileContext.instance.activeProfile != this) + return; + + var playerSettings = (HasSerializedPlayerSettings() && !activeWillBeRemoved) ? m_PlayerSettings : s_GlobalPlayerSettings; + PlayerSettings.SetOverridePlayerSettingsInternal(playerSettings); + } + + internal static void TrySetProjectSettingsAssetAsGlobalManagerPlayerSettings() + { + if (BuildProfileContext.instance.activeProfile != null) + return; + + TryLoadProjectSettingsAssetPlayerSettings(); + if (!PlayerSettings.IsGlobalManagerPlayerSettings(s_GlobalPlayerSettings)) + PlayerSettings.SetOverridePlayerSettingsInternal(s_GlobalPlayerSettings); + } + + internal static bool IsDataEqualToProjectSettings(PlayerSettings targetPlayerSettings) + { + var projectSettingsYaml = PlayerSettings.SerializeAsYAMLString(s_GlobalPlayerSettings); + var targetSettingsYaml = PlayerSettings.SerializeAsYAMLString(targetPlayerSettings); + return projectSettingsYaml == targetSettingsYaml; + } + + static void TryLoadProjectSettingsAssetPlayerSettings() + { + if (s_GlobalPlayerSettings == null) + s_GlobalPlayerSettings = AssetDatabase.LoadAssetAtPath(k_ProjectSettingsAssetPath); + } + } +} diff --git a/Editor/Mono/BuildProfile/Events.cs b/Editor/Mono/BuildProfile/Events.cs new file mode 100644 index 0000000000..f10d0fe892 --- /dev/null +++ b/Editor/Mono/BuildProfile/Events.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 System; +using UnityEngine.Analytics; +using UnityEngine.Scripting; + +namespace UnityEditor.Build.Profile +{ + /// + /// Event for when building an active build profile. + /// + [AnalyticInfo(eventName: "buildProfileBuildTime", vendorKey: "unity.buildprofile")] + internal class BuildProfileBuildTimeEvent : IAnalytic + { + [Serializable] + internal struct Payload : IAnalytic.IData + { + /// + /// Platform ID of the target build profile. + /// + public string platformId; + + /// + /// Platform display name of the target build profile. + /// + public string platformDisplayName; + + /// + /// Unique identifier of the profile asset. Not available + /// for classic platforms. + /// + public string profileAssetGUID; + } + + Payload m_Payload; + + public BuildProfileBuildTimeEvent(Payload payload) + { + this.m_Payload = payload; + } + + public bool TryGatherData(out IAnalytic.IData data, out Exception error) + { + error = null; + data = m_Payload; + return data != null; + } + + [RequiredByNativeCode] + public static void SendBuildProfile() + { + if (!EditorUserBuildSettings.isBuildProfileAvailable) + return; + + var profile = BuildProfile.GetActiveBuildProfile(); + if (profile == null) + return; + + EditorAnalytics.SendAnalytic(new BuildProfileBuildTimeEvent(new BuildProfileBuildTimeEvent.Payload + { + platformId = profile.platformId, + platformDisplayName = BuildProfileModuleUtil.GetClassicPlatformDisplayName(profile.platformId), + profileAssetGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(profile)) + })); + } + } +} diff --git a/Editor/Mono/BuildProfile/SharedPlatformSettings.cs b/Editor/Mono/BuildProfile/SharedPlatformSettings.cs index 6885061a80..956a779785 100644 --- a/Editor/Mono/BuildProfile/SharedPlatformSettings.cs +++ b/Editor/Mono/BuildProfile/SharedPlatformSettings.cs @@ -198,12 +198,14 @@ public string windowsDevicePortalAddress public string windowsDevicePortalUsername { - get => m_WindowsDevicePortalUsername; + get => EditorUserBuildSettings.DecodeBase64(m_WindowsDevicePortalUsername); set { - if (m_WindowsDevicePortalUsername != value) + string encodedString = EditorUserBuildSettings.EncodeBase64(value); + + if (m_WindowsDevicePortalUsername != encodedString) { - m_WindowsDevicePortalUsername = value; + m_WindowsDevicePortalUsername = EditorUserBuildSettings.EncodeBase64(value); SyncSharedSettings(k_SettingWindowsDevicePortalUsername); } } @@ -211,12 +213,14 @@ public string windowsDevicePortalUsername public string windowsDevicePortalPassword { - get => m_WindowsDevicePortalPassword; + get => EditorUserBuildSettings.DecodeBase64(m_WindowsDevicePortalPassword); set { - if (m_WindowsDevicePortalPassword != value) + string encodedString = EditorUserBuildSettings.EncodeBase64(value); + + if (m_WindowsDevicePortalPassword != encodedString) { - m_WindowsDevicePortalPassword = value; + m_WindowsDevicePortalPassword = encodedString; SyncSharedSettings(k_SettingWindowsDevicePortalPassword); } } diff --git a/Editor/Mono/BuildTargetConverter.cs b/Editor/Mono/BuildTargetConverter.cs index 7f32bd4a99..8f6ae8c3a5 100644 --- a/Editor/Mono/BuildTargetConverter.cs +++ b/Editor/Mono/BuildTargetConverter.cs @@ -40,6 +40,8 @@ internal static class BuildTargetConverter return RuntimePlatform.IPhonePlayer; case BuildTarget.tvOS: return RuntimePlatform.tvOS; + case BuildTarget.VisionOS: + return RuntimePlatform.VisionOS; case BuildTarget.WebGL: return RuntimePlatform.WebGLPlayer; case BuildTarget.GameCoreXboxSeries: diff --git a/Editor/Mono/BuildTargetDiscovery.bindings.cs b/Editor/Mono/BuildTargetDiscovery.bindings.cs index 9199e0da15..fd9f3e9992 100644 --- a/Editor/Mono/BuildTargetDiscovery.bindings.cs +++ b/Editor/Mono/BuildTargetDiscovery.bindings.cs @@ -8,6 +8,7 @@ using System.Runtime.InteropServices; using GraphicsDeviceType = UnityEngine.Rendering.GraphicsDeviceType; using UnityEngine.Scripting; +using System.Collections.Generic; namespace UnityEditor { @@ -128,11 +129,11 @@ public static bool TryGetProperties(BuildTarget platform, out T properties) w } public static BuildTarget[] StandaloneBuildTargets { get; internal set; } = new BuildTarget[] - { - BuildTarget.StandaloneOSX, + { + BuildTarget.StandaloneOSX, BuildTarget.StandaloneWindows, - BuildTarget.StandaloneWindows64, - BuildTarget.StandaloneLinux64, + BuildTarget.StandaloneWindows64, + BuildTarget.StandaloneLinux64, }; [RequiredByNativeCode] @@ -175,5 +176,477 @@ internal static bool DoesBuildTargetSupportSinglePassStereoRendering(BuildTarget return false; } + static readonly GUID s_platform_02 = new("0d2129357eac403d8b359c2dcbf82502"); + static readonly GUID s_platform_05 = new("4e3c793746204150860bf175a9a41a05"); + static readonly GUID s_platform_09 = new("ad48d16a66894befa4d8181998c3cb09"); + static readonly GUID s_platform_13 = new("b9b35072a6f44c2e863f17467ea3dc13"); + static readonly GUID s_platform_20 = new("84a3bb9e7420477f885e98145999eb20"); + static readonly GUID s_platform_21 = new("32e92b6f4db44fadb869cafb8184d021"); + static readonly GUID s_platform_24 = new("cb423bfea44b4d658edb8bc5d91a3024"); + static readonly GUID s_platform_31 = new("5d4f9b64eeb74b18a2de0de6f0c36931"); + static readonly GUID s_platform_37 = new("81e4f4c492fd4311bbf5b0b88a28c737"); + static readonly GUID s_platform_38 = new("08d61a9cdfb840119d9bea5588e2f338"); + static readonly GUID s_platform_41 = new("f188349a68c441ec9e3eb4c6f59abd41"); + static readonly GUID s_platform_42 = new("c9f186cd3d594a1496bca1860359f842"); + static readonly GUID s_platform_43 = new("a6f1094111614cba85f0508bf9778843"); + static readonly GUID s_platform_44 = new("e30a9c34166844499a56eaa4ed115c44"); + static readonly GUID s_platform_45 = new("f1d7bec2fd7f42f481c66ef512f47845"); + static readonly GUID s_platform_46 = new("99ef95e1e9b048fa9628d7eed27a8646"); + static readonly GUID s_platform_47 = new("53916e6f1f7240d992977ffa2322b047"); + static readonly GUID s_platform_100 = new("8d1e1bca926649cba89d37a4c66e8b3d"); + static readonly GUID s_platform_101 = new("91d938b35f6f4798811e41f2acf9377f"); + static readonly GUID s_platform_102 = new("8659dec1db6b4fac86149f99f2fa4291"); + + static GUID[] WindowsBuildTargets { get; } = new GUID[] + { + s_platform_02, + s_platform_05, + s_platform_09, + s_platform_13, + s_platform_20, + s_platform_21, + s_platform_24, + s_platform_31, + s_platform_37, + s_platform_38, + s_platform_41, + s_platform_42, + s_platform_43, + s_platform_44, + s_platform_45, + s_platform_46, + s_platform_47, + s_platform_100, + s_platform_101, + s_platform_102, + }; + + static GUID[] MacBuildTargets { get; } = new GUID[] + { + s_platform_02, + s_platform_05, + s_platform_09, + s_platform_13, + s_platform_20, + s_platform_24, + s_platform_37, + s_platform_41, + s_platform_45, + s_platform_46, + s_platform_47, + s_platform_100, + s_platform_101, + s_platform_102, + }; + + static GUID[] LinuxBuildTargets { get; } = new GUID[] + { + s_platform_02, + s_platform_05, + s_platform_09, + s_platform_13, + s_platform_20, + s_platform_24, + s_platform_37, + s_platform_41, + s_platform_45, + s_platform_46, + s_platform_47, + s_platform_100, + s_platform_101, + s_platform_102, + }; + + static GUID[] NDABuildTargets { get; } = new GUID[] + { + s_platform_31, + s_platform_44, + s_platform_38, + }; + + static GUID[] ExternalDownloadForBuildTarget { get; } = new GUID[] + { + s_platform_31, + s_platform_43, + s_platform_44, + }; + + static Dictionary s_PlatformGUIDData = new() + { + { BuildTarget.StandaloneOSX, s_platform_02 }, + { BuildTarget.StandaloneWindows, s_platform_05 }, + { BuildTarget.StandaloneWindows64, s_platform_05 }, // return same build target GUID for Win and Win64 since we only have one + { BuildTarget.iOS, s_platform_09 }, + { BuildTarget.Android, s_platform_13 }, + { BuildTarget.WebGL, s_platform_20 }, + { BuildTarget.WSAPlayer, s_platform_21 }, + { BuildTarget.StandaloneLinux64, s_platform_24 }, + { BuildTarget.PS4, s_platform_31 }, + { BuildTarget.tvOS, s_platform_37 }, + { BuildTarget.Switch, s_platform_38 }, + { BuildTarget.LinuxHeadlessSimulation, s_platform_41 }, + { BuildTarget.GameCoreXboxSeries, s_platform_42 }, + { BuildTarget.GameCoreXboxOne, s_platform_43 }, + { BuildTarget.PS5, s_platform_44 }, + { BuildTarget.EmbeddedLinux, s_platform_45 }, + { BuildTarget.QNX, s_platform_46 }, + { BuildTarget.VisionOS, s_platform_47 }, + }; + + static readonly Dictionary k_PlatformBuildTargetAndSubtargetGUIDData = new() + { + { s_platform_02, (BuildTarget.StandaloneOSX, StandaloneBuildSubtarget.Player) }, + { s_platform_05, (BuildTarget.StandaloneWindows64, StandaloneBuildSubtarget.Player) }, + { s_platform_09, (BuildTarget.iOS, StandaloneBuildSubtarget.Default) }, + { s_platform_13, (BuildTarget.Android, StandaloneBuildSubtarget.Default) }, + { s_platform_20, (BuildTarget.WebGL, StandaloneBuildSubtarget.Default) }, + { s_platform_21, (BuildTarget.WSAPlayer, StandaloneBuildSubtarget.Default) }, + { s_platform_24, (BuildTarget.StandaloneLinux64, StandaloneBuildSubtarget.Player) }, + { s_platform_31, (BuildTarget.PS4, StandaloneBuildSubtarget.Default) }, + { s_platform_37, (BuildTarget.tvOS, StandaloneBuildSubtarget.Default) }, + { s_platform_38, (BuildTarget.Switch, StandaloneBuildSubtarget.Default) }, + { s_platform_41, (BuildTarget.LinuxHeadlessSimulation, StandaloneBuildSubtarget.Default) }, + { s_platform_42, (BuildTarget.GameCoreXboxSeries, StandaloneBuildSubtarget.Default) }, + { s_platform_43, (BuildTarget.GameCoreXboxOne, StandaloneBuildSubtarget.Default) }, + { s_platform_44, (BuildTarget.PS5, StandaloneBuildSubtarget.Default) }, + { s_platform_45, (BuildTarget.EmbeddedLinux, StandaloneBuildSubtarget.Default) }, + { s_platform_46, (BuildTarget.QNX, StandaloneBuildSubtarget.Default) }, + { s_platform_47, (BuildTarget.VisionOS, StandaloneBuildSubtarget.Default) }, + { s_platform_101, (BuildTarget.StandaloneLinux64, StandaloneBuildSubtarget.Server) }, + { s_platform_100, (BuildTarget.StandaloneWindows64, StandaloneBuildSubtarget.Server) }, + { s_platform_102, (BuildTarget.StandaloneOSX, StandaloneBuildSubtarget.Server) }, + }; + + static Dictionary s_PlatformRequiredPackages = new() + { + { s_platform_45, L10n.Tr("") }, //https://github.cds.internal.unity3d.com/unity/unity/blob/690ff735df474658b18a6ce362b64384dd09a889/PlatformDependent/EmbeddedLinux/Extensions/Managed/EmbeddedLinuxToolchainPackageInstaller.cs#L71 and https://github.cds.internal.unity3d.com/unity/unity/blob/690ff735df474658b18a6ce362b64384dd09a889/PlatformDependent/LinuxStandalone/Extensions/Managed/LinuxStandaloneToolchainPackageInstaller.cs#L16 + }; + + static Dictionary s_PlatformRecommendedPackages = new() + { + { s_platform_45, L10n.Tr("") }, + }; + + static Dictionary s_PlatformDescription = new() + { + { s_platform_02, L10n.Tr("Take advantage of Unity’s support for the latest Mac devices with M series chips. The Mac Standalone platform also supports Intel-based Mac devices.") }, + { s_platform_05, L10n.Tr("Access an ecosystem of Unity-supported game development solutions to reach the vast PC gamer audience around the world. Leverage DirectX 12 and inline ray tracing support for cutting edge visual fidelity. Use the Microsoft GDK packages to further unlock the Microsoft gaming ecosystem.") }, + { s_platform_09, L10n.Tr("Benefit from Unity’s longstanding and wide-ranging resources for the entire development lifecycle for iOS games. This includes tools and services for rapid iteration, performance optimization, player engagement, and revenue growth.") }, + { s_platform_13, L10n.Tr("Benefit from Unity’s longstanding and wide-ranging resources for the entire development lifecycle with tools and services for rapid iteration, performance optimization, player engagement, and revenue growth.") }, + { s_platform_20, L10n.Tr("Leverage Unity’s web solutions to offer your players near-instant access to their favorite games, no matter where they want to play. Our web platform support includes key advances that reduce friction for more devices, and take advantage of the latest graphics API to ensure smooth frame rates and exceptional performance for even the most ambitious web games.") }, + { s_platform_21, L10n.Tr("Benefit from Unity’s runtime support for UWP, ensuring you’re able to reach as many users as possible in the Microsoft ecosystem. UWP is used for HoloLens and Windows 10 and 11 devices, among others.") }, + { s_platform_24, L10n.Tr("Leverage Unity’s platform support for Linux, including an ecosystem of game development solutions for creators of all skill levels.") }, + { s_platform_31, L10n.Tr("Create your game with a comprehensive game development platform for PlayStation®4. Discover powerful creation tools to take your PlayStation game development to the next level.") }, + { s_platform_37, L10n.Tr("Choose tvOS if you’re planning to develop applications for Apple TVs. tvOS is based on the iOS operating system and has many similar frameworks, technologies, and concepts.") }, + { s_platform_38, L10n.Tr("Bring your game to Nintendo Switch™ with Unity’s platform support for workflows, integration, and more, plus a dedicated forum.") }, + { s_platform_41, L10n.Tr("") }, + { s_platform_42, L10n.Tr("Attract players around the world on the latest generation of Xbox: Xbox Series X|S. Push the graphical fidelity of your games with inline ray tracing, all while maintaining performance with the latest optimizations for DirectX 12.") }, + { s_platform_43, L10n.Tr("Attract and engage over 50 million players around the world on Xbox One.") }, + { s_platform_44, L10n.Tr("Create your game with a comprehensive game development platform for PlayStation®5. Discover powerful creation tools to take your PlayStation game development to the next level.") }, + { s_platform_45, L10n.Tr("Choose Embedded Linux, a compact version of Linux, if you are planning to build applications for embedded devices and appliances.") }, + { s_platform_46, L10n.Tr("Deploy the Unity runtime to automotive and other embedded systems utilizing the Blackberry® QNX® real-time operating system.") }, + { s_platform_100, L10n.Tr("Benefit from Unity’s support for developing games and applications on the Dedicated Windows Server platform, including publishing multiplayer games.") }, + { s_platform_101, L10n.Tr("Benefit from Unity’s support for developing games and applications on the Dedicated Linux Server platform, including publishing multiplayer games.") }, + { s_platform_102, L10n.Tr("Benefit from Unity’s support for developing games and applications on the Dedicated Mac Server platform, including publishing multiplayer games.") }, + }; + + static Dictionary s_PlatformLink = new() + { + { s_platform_13, L10n.Tr("Unity Android Manual / https://docs.unity3d.com/Manual/android.html") }, + { s_platform_31, L10n.Tr("Register as a PlayStation developer / https://partners.playstation.net/ ") }, + { s_platform_38, L10n.Tr("Register as a Nintendo developer / http://developer.nintendo.com ") }, + { s_platform_42, L10n.Tr("Register as an Xbox developer / https://www.xbox.com/en-US/developers/id ") }, + { s_platform_43, L10n.Tr("Register as an Xbox developer / https://www.xbox.com/en-US/developers/id ") }, + { s_platform_44, L10n.Tr("Register as a PlayStation developer / https://partners.playstation.net/ ") }, + }; + + static Dictionary s_PlatformInstructions = new() + { + { s_platform_02, L10n.Tr("*standard install form hub") }, + { s_platform_05, L10n.Tr("*standard install form hub") }, + { s_platform_09, L10n.Tr("*standard install form hub") }, + { s_platform_13, L10n.Tr("*standard install form hub") }, + { s_platform_20, L10n.Tr("*standard install form hub") }, + { s_platform_21, L10n.Tr("*standard install form hub") }, + { s_platform_24, L10n.Tr("*standard install form hub") }, + { s_platform_31, L10n.Tr("This platform is not available to download from the Unity website, contact the platform holder directly to learn more.") }, + { s_platform_37, L10n.Tr("*standard install form hub") }, + { s_platform_38, L10n.Tr("This platform is not available to download from the Unity website, contact the platform holder directly to learn more.") }, + { s_platform_41, L10n.Tr("*standard install form hub") }, + { s_platform_42, L10n.Tr("This platform is not available to download from the Unity website, contact the platform holder directly to learn more.") }, + { s_platform_43, L10n.Tr("This platform is not available to download from the Unity website, contact the platform holder directly to learn more.") }, + { s_platform_44, L10n.Tr("This platform is not available to download from the Unity website, contact the platform holder directly to learn more.") }, + { s_platform_45, L10n.Tr("As the Embedded Linux platform for Unity is not yet available to download from the Unity website, contact your Account Manager or the Unity Sales team to get access.") }, + { s_platform_46, L10n.Tr("As the QNX platform for Unity is not yet available to download from the Unity website, contact your Account Manager or the Unity Sales team to get access.") }, + { s_platform_47, L10n.Tr("*standard install form hub") }, + { s_platform_100, L10n.Tr("*standard install form hub") }, + { s_platform_101, L10n.Tr("*standard install form hub") }, + { s_platform_102, L10n.Tr("*standard install form hub") }, + }; + + // Name changes here must be reflected in the platform [PLATFORM]BuildTarget.cs and [Platfrom]BuildTarget.cpp respective DisplayName and niceName + static Dictionary s_PlatformDisplayName = new() + { + { s_platform_02, "macOS" }, + { s_platform_05, "Windows" }, + { s_platform_09, "iOS" }, + { s_platform_13, "Android™" }, + { s_platform_20, "WebGL" }, + { s_platform_21, "Universal Windows Platform" }, + { s_platform_24, "Linux" }, + { s_platform_31, "PlayStation®4" }, + { s_platform_37, "tvOS" }, + { s_platform_38, "Nintendo Switch™" }, + { s_platform_41, "Linux Headless Simulation" }, + { s_platform_42, "Xbox Series X|S" }, + { s_platform_43, "Xbox One" }, + { s_platform_44, "PlayStation®5" }, + { s_platform_45, "Embedded Linux" }, + { s_platform_46, "QNX®" }, + { s_platform_47, "visionOS" }, + { s_platform_100, "Windows Server" }, + { s_platform_101, "Linux Server" }, + { s_platform_102, "Mac Server" }, + }; + + public static GUID GetGUIDFromBuildTarget(BuildTarget buildTarget) + { + if(s_PlatformGUIDData.TryGetValue(buildTarget, out GUID value)) + return value; + + return new GUID(""); + } + + public static GUID GetGUIDFromBuildTarget(NamedBuildTarget namedBuildTarget, BuildTarget buildTarget) + { + if (namedBuildTarget == NamedBuildTarget.Server) + { + if (buildTarget == BuildTarget.StandaloneWindows || buildTarget == BuildTarget.StandaloneWindows64) + return s_platform_100; + else if (buildTarget == BuildTarget.StandaloneLinux64) + return s_platform_101; + else if (buildTarget == BuildTarget.StandaloneOSX) + return s_platform_102; + } + + return GetGUIDFromBuildTarget(buildTarget); + } + + public static (BuildTarget, StandaloneBuildSubtarget) GetBuildTargetAndSubtargetFromGUID(GUID guid) + { + if (k_PlatformBuildTargetAndSubtargetGUIDData.TryGetValue(guid, out var value)) + return value; + + return (BuildTarget.NoTarget, StandaloneBuildSubtarget.Default); + } + + //TODO: PLAT-8696 BuildPlatformIsInstalled does not support server platforms yet + [System.Obsolete("BuildPlatformIsInstalled(BuildTarget) is obsolete. Use BuildPlatformIsInstalled(IBuildTarget) instead.", false)] + + public static bool BuildPlatformIsInstalled(BuildTarget platform) + { + return BuildPipeline.GetPlaybackEngineDirectory(platform, BuildOptions.None, true) != string.Empty; + } + + public static bool BuildPlatformIsInstalled(IBuildTarget platform) + { + return BuildPipeline.GetPlaybackEngineDirectory((BuildTarget)platform.GetLegacyId, BuildOptions.None, true) != string.Empty; + } + + [System.Obsolete("BuildPlatformIsAvailableOnHostPlatform(BuildTarget) is obsolete. Use BuildPlatformIsAvailableOnHostPlatform(IBuildTarget) instead.", false)] + + public static bool BuildPlatformIsAvailableOnHostPlatform(BuildTarget platform, UnityEngine.OperatingSystemFamily hostPlatform) + { + var platformGuid = GetGUIDFromBuildTarget(platform); + + if (hostPlatform == UnityEngine.OperatingSystemFamily.Windows) + { + foreach (var winTarget in WindowsBuildTargets) + if (winTarget == platformGuid) + return true; + } + else if (hostPlatform == UnityEngine.OperatingSystemFamily.MacOSX) + { + foreach (var macTarget in MacBuildTargets) + if (macTarget == platformGuid) + return true; + } + else if (hostPlatform == UnityEngine.OperatingSystemFamily.Linux) + { + foreach (var linuxTarget in LinuxBuildTargets) + if (linuxTarget == platformGuid) + return true; + } + return false; + } + public static bool BuildPlatformIsAvailableOnHostPlatform(IBuildTarget platform, UnityEngine.OperatingSystemFamily hostPlatform) + { + // TODO: PLAT-8695 - Consoles are available only on x64 Windows. They can't build on Arm64. Windows.x64 and arm64 have different compability in platforms + if (hostPlatform == UnityEngine.OperatingSystemFamily.Windows) + foreach (var winTarget in WindowsBuildTargets) + if (winTarget == platform.Guid) + return true; + + else if(hostPlatform == UnityEngine.OperatingSystemFamily.MacOSX) + foreach (var macTarget in MacBuildTargets) + if (macTarget == platform.Guid) + return true; + + else if (hostPlatform == UnityEngine.OperatingSystemFamily.Linux) + foreach (var linuxTarget in LinuxBuildTargets) + if (linuxTarget == platform.Guid) + return true; + + return false; + } + [System.Obsolete("BuildPlatformCanBeInstalledWithHub(BuildTarget) is obsolete. Use BuildPlatformCanBeInstalledWithHub(IBuildTarget) instead.", false)] + + public static bool BuildPlatformCanBeInstalledWithHub(BuildTarget platform) + { + foreach (var target in ExternalDownloadForBuildTarget) + if (target == GetGUIDFromBuildTarget(platform)) + return false; + + return true; + } + + public static bool BuildPlatformCanBeInstalledWithHub(IBuildTarget platform) + { + foreach (var invisibleTarget in ExternalDownloadForBuildTarget) + if (invisibleTarget == platform.Guid) + return false; + + return true; + } + + [System.Obsolete("BuildPlatformIsUnderNDA(BuildTarget) is obsolete. Use BuildPlatformIsUnderNDA(IBuildTarget) instead.", false)] + + public static bool BuildPlatformIsUnderNDA(BuildTarget platform) + { + foreach (var ndaTarget in NDABuildTargets) + if (ndaTarget == GetGUIDFromBuildTarget(platform)) + return true; + + return false; + } + + public static bool BuildPlatformIsUnderNDA(IBuildTarget platform) + { + foreach (var ndaTarget in NDABuildTargets) + if (ndaTarget == platform.Guid) + return true; + + return false; + } + + [System.Obsolete("BuildPlatformRecommendeddPackages(BuildTarget) is obsolete. Use BuildPlatformRecommendeddPackages(IBuildTarget) instead.", false)] + + + public static string BuildPlatformRecommendeddPackages(BuildTarget platform) + { + if (s_PlatformRecommendedPackages.TryGetValue(GetGUIDFromBuildTarget(platform), out string recommendedPackages)) + return recommendedPackages; + + return ""; + } + + public static string BuildPlatformRecommendeddPackages(IBuildTarget platform) + { + if (s_PlatformRecommendedPackages.TryGetValue(platform.Guid, out string recommendedPackages)) + return recommendedPackages; + + return ""; + } + + [System.Obsolete("BuildPlatformDescription(BuildTarget) is obsolete. Use BuildPlatformDescription(IBuildTarget) instead.", false)] + + public static string BuildPlatformDescription(BuildTarget platform) + { + if (s_PlatformDescription.TryGetValue(GetGUIDFromBuildTarget(platform), out string description)) + return description; + + return ""; + } + + public static string BuildPlatformDescription(IBuildTarget platform) + { + if (s_PlatformDescription.TryGetValue(platform.Guid, out string description)) + return description; + + return ""; + } + + [System.Obsolete("BuildPlatformDocumentationLink(BuildTarget) is obsolete. Use BuildPlatformDocumentationLink(IBuildTarget) instead.", false)] + + public static string BuildPlatformDocumentationLink(BuildTarget platform) + { + if (s_PlatformLink.TryGetValue(GetGUIDFromBuildTarget(platform), out string link)) + return link; + + return ""; + } + + public static string BuildPlatformDocumentationLink(IBuildTarget platform) + { + if (s_PlatformLink.TryGetValue(platform.Guid, out string link)) + return link; + + return ""; + } + + [System.Obsolete("BuildPlatformOnboardingInstructions(BuildTarget) is obsolete. Use BuildPlatformOnboardingInstructions(IBuildTarget) instead.", false)] + + public static string BuildPlatformOnboardingInstructions(BuildTarget platform) + { + if (s_PlatformInstructions.TryGetValue(GetGUIDFromBuildTarget(platform), out string instructions)) + return instructions; + + return ""; + } + + public static string BuildPlatformOnboardingInstructions(IBuildTarget platform) + { + if (s_PlatformInstructions.TryGetValue(platform.Guid, out string instructions)) + return instructions; + + return ""; + } + + [System.Obsolete("BuildPlatformDisplayName(BuildTarget) is obsolete. Use BuildPlatformDisplayName(IBuildTarget) instead.", false)] + public static string BuildPlatformDisplayName(BuildTarget platform) + { + if (s_PlatformDisplayName.TryGetValue(GetGUIDFromBuildTarget(platform), out string displayName)) + return displayName; + + return ""; + } + + public static string BuildPlatformDisplayName(IBuildTarget platform) + { + if (s_PlatformDisplayName.TryGetValue(platform.Guid, out string displayName)) + return displayName; + + return ""; + } + + [System.Obsolete("BuildPlatformDisplayName(BuildTarget) is obsolete. Use BuildPlatformDisplayName(IBuildTarget) instead.", false)] + public static string BuildPlatformDisplayName(NamedBuildTarget namedBuildTarget, BuildTarget buildTarget) + { + var guid = GetGUIDFromBuildTarget(buildTarget); + + if (namedBuildTarget == NamedBuildTarget.Server) + { + if (buildTarget == BuildTarget.StandaloneWindows || buildTarget == BuildTarget.StandaloneWindows64) + guid = s_platform_100; + else if (buildTarget == BuildTarget.StandaloneLinux64) + guid = s_platform_101; + else if (buildTarget == BuildTarget.StandaloneOSX) + guid = s_platform_102; + } + if (s_PlatformDisplayName.TryGetValue(guid, out string displayName)) + return displayName; + + return ""; + } } } diff --git a/Editor/Mono/Collab/AssetAccess.cs b/Editor/Mono/Collab/AssetAccess.cs deleted file mode 100644 index d210133b58..0000000000 --- a/Editor/Mono/Collab/AssetAccess.cs +++ /dev/null @@ -1,127 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace UnityEditor.Collaboration -{ - internal static class AssetAccess - { - // Attempts to retrieve the Asset GUID within the Unity Object. - // Failure: returns false and the given 'assetGUID' is set to empty string. - // Success: returns true and updates 'assetGUID'. - public static bool TryGetAssetGUIDFromObject(UnityEngine.Object objectWithGUID, out string assetGUID) - { - if (objectWithGUID == null) - { - throw new ArgumentNullException("objectWithGuid"); - } - - bool success = false; - - if (objectWithGUID.GetType() == typeof(SceneAsset)) - { - success = TryGetAssetGUIDFromDatabase(objectWithGUID, out assetGUID); - } - else if (objectWithGUID.GetType() == typeof(GameObject)) - { - success = TryGetPrefabGUID(objectWithGUID, out assetGUID); - } - else - { - assetGUID = String.Empty; - } - return success; - } - - // Attempts to retrieve the Asset corresponding to the given GUID. - // Failure: returns false and the given 'asset' is set to null. - // Success: returns true and updates 'asset'. - public static bool TryGetAssetFromGUID(string assetGUID, out UnityEngine.Object asset) - { - if (assetGUID == null) - { - throw new ArgumentNullException("assetGUID"); - } - - bool success = false; - string objectPath = AssetDatabase.GUIDToAssetPath(assetGUID); - - if (objectPath == null) - { - asset = null; - } - else - { - asset = AssetDatabase.LoadMainAssetAtPath(objectPath); - success = (asset != null); - } - return success; - } - - // Expects the given 'gameObject' to have a 'PrefabType' which - // is either an 'instance' or straight prefab. - // Failure: assigns empty string to 'assetGUID', returns false. - // Success: assigns the retrieval of the GUID to 'assetGUID' and returns true. - private static bool TryGetPrefabGUID(UnityEngine.Object gameObject, out string assetGUID) - { - UnityEngine.Object prefabObject = null; - - if (PrefabUtility.IsPartOfNonAssetPrefabInstance(gameObject)) - { - prefabObject = PrefabUtility.GetCorrespondingObjectFromSource(gameObject); - } - else if (PrefabUtility.IsPartOfPrefabAsset(gameObject)) - { - prefabObject = gameObject; - } - - bool success = false; - - if (prefabObject == null) - { - assetGUID = String.Empty; - } - else - { - success = TryGetAssetGUIDFromDatabase(prefabObject, out assetGUID); - } - return success; - } - - // Interacts with 'AssetDatabase' to retrieve 'objectWithGUID' path - // and in-turn uses this to access the GUID. - // Failure: assigns an empty string to 'assetGUID', returns false. - // Success: assigns the GUID result from 'AssetDatabase' to 'assetGUID' and returns true. - private static bool TryGetAssetGUIDFromDatabase(UnityEngine.Object objectWithGUID, out string assetGUID) - { - if (objectWithGUID == null) - { - throw new ArgumentNullException("objectWithGuid"); - } - - string _assetGUID = null; - string objectPath = AssetDatabase.GetAssetPath(objectWithGUID); - - if (!String.IsNullOrEmpty(objectPath)) - { - _assetGUID = AssetDatabase.AssetPathToGUID(objectPath); - } - - bool success = false; - if (String.IsNullOrEmpty(_assetGUID)) - { - assetGUID = String.Empty; - } - else - { - assetGUID = _assetGUID; - success = true; - } - return success; - } - } -} diff --git a/Editor/Mono/Collab/CollabTesting.cs b/Editor/Mono/Collab/CollabTesting.cs deleted file mode 100644 index d244a0443a..0000000000 --- a/Editor/Mono/Collab/CollabTesting.cs +++ /dev/null @@ -1,90 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.Scripting; - -namespace UnityEditor.Collaboration -{ - internal class CollabTesting - { - [Flags] - public enum AsyncState - { - NotWaiting = 0, - WaitForJobComplete, - WaitForChannelMessageHandled - } - - private static IEnumerator _enumerator = null; - private static Action _runAfter = null; - private static AsyncState _nextState = AsyncState.NotWaiting; - - public static Func> Tick - { - set { _enumerator = value().GetEnumerator(); } - } - - public static Action AfterRun - { - set { _runAfter = value; } - } - - public static bool IsRunning - { - get { return _enumerator != null; } - } - - public static void OnJobsCompleted() - { - OnAsyncSignalReceived(AsyncState.WaitForJobComplete); - } - - [RequiredByNativeCode] - public static void OnChannelMessageHandled() - { - OnAsyncSignalReceived(AsyncState.WaitForChannelMessageHandled); - } - - private static void OnAsyncSignalReceived(AsyncState stateToRemove) - { - if ((_nextState & stateToRemove) == 0) - return; - - _nextState &= ~stateToRemove; - if (_nextState == AsyncState.NotWaiting) - Execute(); - } - - public static void Execute() - { - if (_enumerator == null) - return; - - try - { - if (!_enumerator.MoveNext()) - End(); - else - _nextState = _enumerator.Current; - } - catch (Exception) - { - Debug.LogError("Something Went wrong with the test framework itself"); - throw; - } - } - - public static void End() - { - if (_enumerator != null) - { - _runAfter(); - _enumerator = null; - } - } - } -} diff --git a/Editor/Mono/ContainerWindow.cs b/Editor/Mono/ContainerWindow.cs index 87bc7c0a9c..03715f26fe 100644 --- a/Editor/Mono/ContainerWindow.cs +++ b/Editor/Mono/ContainerWindow.cs @@ -29,7 +29,7 @@ internal partial class ContainerWindow : ScriptableObject [SerializeField] Vector2 m_MaxSize = new Vector2(8192, 8192); [SerializeField] bool m_Maximized; - internal bool m_IsMppmCloneWindow; + static readonly bool k_IsMultiplayerClone = Array.Exists(Environment.GetCommandLineArgs(), arg => arg == "--virtual-project-clone"); internal bool m_DontSaveToLayout = false; private bool m_HasUnsavedChanges = false; @@ -45,6 +45,7 @@ internal partial class ContainerWindow : ScriptableObject static internal bool s_Modal = false; private static ContainerWindow s_MainWindow; + static internal ContainerWindow mainWindow { get => s_MainWindow; } static readonly string s_ContextMenuID = "UnityEditor.UIElements.EditorMenuExtensions+ContextMenu"; @@ -429,7 +430,7 @@ private void RequestCloseSentByNativeCode() [RequiredByNativeCode] internal bool IsMultiplayerClone() { - return m_IsMppmCloneWindow; + return k_IsMultiplayerClone; } private static List FindUnsavedChanges(View view) diff --git a/Editor/Mono/EditorGUI.cs b/Editor/Mono/EditorGUI.cs index 59d6f250ec..56200b0b2b 100644 --- a/Editor/Mono/EditorGUI.cs +++ b/Editor/Mono/EditorGUI.cs @@ -7681,19 +7681,7 @@ internal static bool DefaultPropertyField(Rect position, SerializedProperty prop } case SerializedPropertyType.RenderingLayerMask: { - var names = RenderingLayerMask.GetDefinedRenderingLayerNames(); - var values = RenderingLayerMask.GetDefinedRenderingLayerValues(); - MaskFieldGUI.GetMaskButtonValue((int) property.uintValue, names, values, out var toggleLabel, out var toggleLabelMixed); - if (label != null) - position = PrefixLabel(position, label, EditorStyles.label); - - var toggleLabelContent = property.hasMultipleDifferentValues ? mixedValueContent : MaskFieldGUI.DoMixedLabel(toggleLabel, toggleLabelMixed, position, EditorStyles.layerMaskField); - bool toggled = DropdownButton(position, toggleLabelContent, FocusType.Keyboard, EditorStyles.layerMaskField); - if (toggled) - { - PopupWindowWithoutFocus.Show(position, new MaskFieldDropDown(property)); - GUIUtility.ExitGUI(); - } + RenderingLayerMaskField(position, label, property); break; } case SerializedPropertyType.Character: diff --git a/Editor/Mono/EditorUserBuildSettings.bindings.cs b/Editor/Mono/EditorUserBuildSettings.bindings.cs index 28d2efa79b..a4ff9de98c 100644 --- a/Editor/Mono/EditorUserBuildSettings.bindings.cs +++ b/Editor/Mono/EditorUserBuildSettings.bindings.cs @@ -676,6 +676,35 @@ public static extern string windowsDevicePortalAddress set; } + internal static string EncodeBase64(string plainText) + { + if (plainText == null) + { + plainText = string.Empty; + } + + var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText); + return Convert.ToBase64String(plainTextBytes); + } + + internal static string DecodeBase64(string base64Text) + { + if (base64Text == null) + { + base64Text = string.Empty; + } + + try + { + var base64EncodedBytes = System.Convert.FromBase64String(base64Text); + return System.Text.Encoding.UTF8.GetString(base64EncodedBytes); + } + catch (FormatException) + { + return string.Empty; + } + } + public static extern string windowsDevicePortalUsername { [NativeMethod("GetWindowsDevicePortalUsername")] @@ -685,6 +714,8 @@ public static extern string windowsDevicePortalUsername } // WDP password is not to be saved with other settings and only stored in memory until Editor is closed + private static string internal_windowsDevicePortalPassword; + public static string windowsDevicePortalPassword { get @@ -694,28 +725,34 @@ public static string windowsDevicePortalPassword { var settings = profile.platformBuildProfile; return settings.GetSharedSetting(SharedPlatformSettings.k_SettingWindowsDevicePortalPassword); + } - return null; + return DecodeBase64(internal_windowsDevicePortalPassword); } set { var profile = BuildProfileContext.GetActiveOrClassicBuildProfile(BuildTarget.NoTarget, StandaloneBuildSubtarget.Default, SharedPlatformSettings.k_SettingWindowsDevicePortalPassword); if (profile == null) - return; - - if (profile.buildTarget == BuildTarget.NoTarget) { - var sharedPlatformSettings = profile.platformBuildProfile as SharedPlatformSettings; - // This will sync the value to applicable classic profiles through the shared profile. - sharedPlatformSettings.windowsDevicePortalPassword = value; + internal_windowsDevicePortalPassword = EncodeBase64(value); } else { - var settings = profile.platformBuildProfile; - // SetSharedSetting() is used to avoid having to cast the active custom profile to platform profiles. - // This only changes the value in the active custom profile and has no effect on syncing. - settings.SetSharedSetting(SharedPlatformSettings.k_SettingWindowsDevicePortalPassword, value); + if (profile.buildTarget == BuildTarget.NoTarget) + { + var sharedPlatformSettings = profile.platformBuildProfile as SharedPlatformSettings; + // This will sync the value to applicable classic profiles through the shared profile. + sharedPlatformSettings.windowsDevicePortalPassword = value; + + } + else + { + var settings = profile.platformBuildProfile; + // SetSharedSetting() is used to avoid having to cast the active custom profile to platform profiles. + // This only changes the value in the active custom profile and has no effect on syncing. + settings.SetSharedSetting(SharedPlatformSettings.k_SettingWindowsDevicePortalPassword, value); + } } } } @@ -1080,5 +1117,8 @@ public static int managedDebuggerFixedPort internal static extern bool isBuildProfileAvailable { get; set; } internal static extern void CopyFromBuildProfile(ScriptableObject buildProfile); internal static extern void CopyToBuildProfile(ScriptableObject buildProfile); + + internal static extern void SetBuildProfilePath(string path); + internal static extern string[] GetActiveProfileYamlScriptingDefines(); } } diff --git a/Editor/Mono/EditorUtility.cs b/Editor/Mono/EditorUtility.cs index 14e69bb219..4df6ccb657 100644 --- a/Editor/Mono/EditorUtility.cs +++ b/Editor/Mono/EditorUtility.cs @@ -626,7 +626,7 @@ internal static void Internal_DisplayPopupMenu(Rect position, string menuItemPat internal static void ConfigurePreviewObjectSRP(GameObject go) { - if (GraphicsSettings.renderPipelineAsset != null && + if (GraphicsSettings.isScriptableRenderPipelineEnabled && go.TryGetComponent(out var renderer)) { // Case 1297670: Force the ambient probe for object preview in SRP. diff --git a/Editor/Mono/EditorWindow.cs b/Editor/Mono/EditorWindow.cs index 601d0984f1..1508dbf5fc 100644 --- a/Editor/Mono/EditorWindow.cs +++ b/Editor/Mono/EditorWindow.cs @@ -49,6 +49,7 @@ public partial class EditorWindow : ScriptableObject internal Rect m_Pos = new Rect(0, 0, 320, 550); [SerializeField] + [HideInInspector] internal DataModeController m_SerializedDataModeController; public IDataModeController dataModeController => GetDataModeController_Internal(); // For each editor window. internal DataModeController GetDataModeController_Internal() // For HostView to use internally. @@ -752,11 +753,26 @@ static void AssignTitle(EditorWindow win, string title) } // Returns the first EditorWindow of type /t/ which is currently on the screen. - static EditorWindow GetWindowPrivate(System.Type t, bool utility, string title, bool focus) + static EditorWindow GetWindowPrivate(System.Type t, bool utility, string title, bool focus, bool includeInheritingClasses = true) { UnityEngine.Object[] wins = Resources.FindObjectsOfTypeAll(t); EditorWindow win = wins.Length > 0 ? (EditorWindow)(wins[0]) : null; + if(win != null && !includeInheritingClasses) + { + if(win.GetType().IsSubclassOf(t)) + { + win = null; + for(int i = 1; i() where T : EditorWindow + { + return GetWindowPrivate(typeof(T), false, null, true, false) as T; + } + public static T GetWindow() where T : EditorWindow { return GetWindow(false, null, true); diff --git a/Editor/Mono/GI/DeviceContext.bindings.cs b/Editor/Mono/GI/DeviceContext.bindings.cs index 9fa1807f26..c7ef9bbf99 100644 --- a/Editor/Mono/GI/DeviceContext.bindings.cs +++ b/Editor/Mono/GI/DeviceContext.bindings.cs @@ -103,8 +103,12 @@ public interface IDeviceContext : IDisposable bool Initialize(); BufferID CreateBuffer(UInt64 size); void DestroyBuffer(BufferID id); - EventID WriteBuffer(BufferSlice dst, NativeArray src) where T : struct; - EventID ReadBuffer(BufferSlice src, NativeArray dst) where T : struct; + void WriteBuffer(BufferSlice dst, NativeArray src) where T : struct; + void ReadBuffer(BufferSlice src, NativeArray dst) where T : struct; + void WriteBuffer(BufferSlice dst, NativeArray src, EventID id) where T : struct; + void ReadBuffer(BufferSlice src, NativeArray dst, EventID id) where T : struct; + EventID CreateEvent(); + void DestroyEvent(EventID id); bool IsCompleted(EventID id); bool Wait(EventID id); bool Flush(); @@ -142,21 +146,36 @@ public void DestroyBuffer(BufferID id) buffers[id].Dispose(); buffers.Remove(id); } - public EventID WriteBuffer(BufferSlice dst, NativeArray src) + public void WriteBuffer(BufferSlice dst, NativeArray src) where T : struct { Debug.Assert(buffers.ContainsKey(dst.Id), "Invalid buffer ID given."); var dstBuffer = buffers[dst.Id].Reinterpret(1); dstBuffer.GetSubArray((int)dst.Offset, dstBuffer.Length - (int)dst.Offset).CopyFrom(src); - return new EventID(); } - public EventID ReadBuffer(BufferSlice src, NativeArray dst) + public void ReadBuffer(BufferSlice src, NativeArray dst) where T : struct { Debug.Assert(buffers.ContainsKey(src.Id), "Invalid buffer ID given."); var srcBuffer = buffers[src.Id].Reinterpret(1); dst.CopyFrom(srcBuffer.GetSubArray((int)src.Offset, srcBuffer.Length - (int)src.Offset)); - return new EventID { Value = nextFreeEventId++ }; + } + public void WriteBuffer(BufferSlice dst, NativeArray src, EventID id) + where T : struct + { + WriteBuffer(dst, src); + } + public void ReadBuffer(BufferSlice src, NativeArray dst, EventID id) + where T : struct + { + ReadBuffer(src, dst); + } + public EventID CreateEvent() + { + return new EventID(nextFreeEventId++); + } + public void DestroyEvent(EventID id) + { } public bool IsCompleted(EventID id) { diff --git a/Editor/Mono/GI/InputExtraction.bindings.cs b/Editor/Mono/GI/InputExtraction.bindings.cs index 0a3333d437..3ba0f4c29f 100644 --- a/Editor/Mono/GI/InputExtraction.bindings.cs +++ b/Editor/Mono/GI/InputExtraction.bindings.cs @@ -70,6 +70,8 @@ internal static class BindingsMarshaller public static extern bool ExtractFromScene(string outputFolderPath, LightBaker.BakeInput input, SourceMap map); + public static extern int[] ComputeOcclusionLightIndicesFromBakeInput(LightBaker.BakeInput bakeInput, UnityEngine.Vector3[] probePositions, uint maxLightsPerProbe); + private static string LookupGameObjectName(SourceMap map, int instanceIndex) { if (map == null) diff --git a/Editor/Mono/GI/InputExtraction.cs b/Editor/Mono/GI/InputExtraction.cs index 6141d4aa2a..2ac3896869 100644 --- a/Editor/Mono/GI/InputExtraction.cs +++ b/Editor/Mono/GI/InputExtraction.cs @@ -42,5 +42,10 @@ internal static bool DeserializeBakeInput(string path, out InputExtraction.BakeI bakeInput = new BakeInput(lightBakerBakeInput); return LightBaker.Deserialize(path, bakeInput.bakeInput); } + + public static int[] ComputeOcclusionLightIndicesFromBakeInput(BakeInput bakeInput, Vector3[] probePositions, uint maxLightsPerProbe = 4) + { + return UnityEditor.LightBaking.InputExtraction.ComputeOcclusionLightIndicesFromBakeInput(bakeInput.bakeInput, probePositions, maxLightsPerProbe); + } } } diff --git a/Editor/Mono/GI/Lightmapping.bindings.cs b/Editor/Mono/GI/Lightmapping.bindings.cs index 17f4c8ca4f..210abf029b 100644 --- a/Editor/Mono/GI/Lightmapping.bindings.cs +++ b/Editor/Mono/GI/Lightmapping.bindings.cs @@ -716,6 +716,7 @@ public static bool Bake(Scene targetScene) [NativeName("Bake")] static extern bool BakeScene(Scene targetScene); + [Obsolete("Please use UnityEngine.LightTransport.IProbeIntegrator instead.", false)] public static event Action additionalBakedProbesCompleted; [RequiredByNativeCode] @@ -728,7 +729,7 @@ internal static void Internal_CallAdditionalBakedProbesCompleted() [FreeFunction] internal unsafe static extern bool GetAdditionalBakedProbes(int id, void* outBakedProbeSH, void* outBakedProbeValidity, void* outBakedProbeOctahedralDepth, int outBakedProbeCount); - [Obsolete("Please use the new GetAdditionalBakedProbes with added octahedral depth map data.", false)] + [Obsolete("Please use UnityEngine.LightTransport.IProbeIntegrator instead.", false)] public unsafe static bool GetAdditionalBakedProbes(int id, NativeArray outBakedProbeSH, NativeArray outBakedProbeValidity) { const int octahedralDepthMapTexelCount = 64; // 8*8 @@ -737,7 +738,7 @@ public unsafe static bool GetAdditionalBakedProbes(int id, NativeArray outBakedProbeSH, Span outBakedProbeValidity, Span outBakedProbeOctahedralDepth) { const int octahedralDepthMapTexelCount = 64; // 8*8 @@ -762,6 +763,7 @@ public unsafe static bool GetAdditionalBakedProbes(int id, Span outBakedProbeSH, NativeArray outBakedProbeValidity, NativeArray outBakedProbeOctahedralDepth) { if (outBakedProbeSH == null || !outBakedProbeSH.IsCreated || @@ -794,16 +796,18 @@ public unsafe static bool GetAdditionalBakedProbes(int id, NativeArray positions) { SetAdditionalBakedProbes(id, positions, true); } [FreeFunction] + [Obsolete("Please use UnityEngine.LightTransport.IProbeIntegrator instead.", false)] public static extern void SetAdditionalBakedProbes(int id, ReadOnlySpan positions, bool dering); [FreeFunction] diff --git a/Editor/Mono/GI/PostProcessing.bindings.cs b/Editor/Mono/GI/PostProcessing.bindings.cs index df0e9e99f7..126996033c 100644 --- a/Editor/Mono/GI/PostProcessing.bindings.cs +++ b/Editor/Mono/GI/PostProcessing.bindings.cs @@ -619,11 +619,13 @@ public bool DeringSphericalHarmonicsL2(IDeviceContext context, BufferSlice(probeCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); using var shOutputBuffer = new NativeArray(probeCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); - EventID eventId = context.ReadBuffer(shIn, shInputBuffer); + EventID eventId = context.CreateEvent(); + context.ReadBuffer(shIn, shInputBuffer, eventId); bool flushResult = context.Flush(); Debug.Assert(flushResult, "Failed to flush context."); bool waitResult = context.Wait(eventId); Debug.Assert(waitResult, "Failed to read SH from context."); + context.DestroyEvent(eventId); // Currently windowing is done on CPU since the algorithm is not GPU friendly. // Since we aren't attempting to port this to GPU, we are using the jobified CPU version. @@ -636,9 +638,11 @@ public bool DeringSphericalHarmonicsL2(IDeviceContext context, BufferSlice radianceEstimateOut); public Result IntegrateValidity(IDeviceContext context, int positionOffset, int positionCount, int sampleCount, BufferSlice validityEstimateOut); + public Result IntegrateOcclusion(IDeviceContext context, int positionOffset, int positionCount, int sampleCount, + int maxLightsPerProbe, BufferSlice perProbeLightIndices, BufferSlice probeOcclusionEstimateOut); } internal class WintermuteProbeIntegrator : IProbeIntegrator { @@ -79,9 +81,13 @@ public unsafe IProbeIntegrator.Result IntegrateDirectRadiance(IDeviceContext con Debug.Assert(context is WintermuteContext, "Expected WintermuteContext but got something else."); var wmContext = context as WintermuteContext; using var positions = new NativeArray(positionCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); - EventID eventId = context.ReadBuffer(_positions, positions); + BufferSlice offsetPositions = _positions; + offsetPositions.Offset += (ulong)positionOffset; + EventID eventId = context.CreateEvent(); + context.ReadBuffer(offsetPositions, positions, eventId); bool waitResult = context.Wait(eventId); Debug.Assert(waitResult, "Failed to read positions from context."); + context.DestroyEvent(eventId); var positionsPtr = (Vector3*)positions.GetUnsafePtr(); using var radianceBuffer = new NativeArray(positionCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); void* shPtr = NativeArrayUnsafeUtility.GetUnsafePtr(radianceBuffer); @@ -89,16 +95,18 @@ public unsafe IProbeIntegrator.Result IntegrateDirectRadiance(IDeviceContext con int giSampleCount = 0; int envSampleCount = 0; const bool ignoreIndirectEnvironment = true; - var lightBakerResult = LightBaker.IntegrateProbeDirectRadianceWintermute(positionsPtr, _integrationContext, positionOffset, positionCount, _pushoff, + var lightBakerResult = LightBaker.IntegrateProbeDirectRadianceWintermute(positionsPtr, _integrationContext, positionCount, _pushoff, _bounceCount, directSampleCount, giSampleCount, envSampleCount, ignoreDirectEnvironment, ignoreIndirectEnvironment, wmContext, _progress, shPtr); // TODO: Fix this in LIGHT-1479, synchronization and read-back should be done by the user. if (lightBakerResult.type != LightBaker.ResultType.Success) return lightBakerResult.ConvertToIProbeIntegratorResult(); - eventId = context.WriteBuffer(radianceEstimateOut, radianceBuffer); + eventId = context.CreateEvent(); + context.WriteBuffer(radianceEstimateOut, radianceBuffer, eventId); waitResult = context.Wait(eventId); Debug.Assert(waitResult, "Failed to write radiance to context."); + context.DestroyEvent(eventId); if (!waitResult) lightBakerResult = new LightBaker.Result {type = LightBaker.ResultType.IOFailed, message = "Failed to write radiance to context."}; @@ -111,9 +119,13 @@ public unsafe IProbeIntegrator.Result IntegrateIndirectRadiance(IDeviceContext c Debug.Assert(context is WintermuteContext, "Expected WintermuteContext but got something else."); var wmContext = context as WintermuteContext; using var positions = new NativeArray(positionCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); - EventID eventId = context.ReadBuffer(_positions, positions); + BufferSlice offsetPositions = _positions; + offsetPositions.Offset += (ulong)positionOffset; + EventID eventId = context.CreateEvent(); + context.ReadBuffer(offsetPositions, positions, eventId); bool waitResult = context.Wait(eventId); Debug.Assert(waitResult, "Failed to read positions from context."); + context.DestroyEvent(eventId); var positionsPtr = (Vector3*)NativeArrayUnsafeUtility.GetUnsafePtr(positions); using var radianceBuffer = new NativeArray(positionCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); void* shPtr = NativeArrayUnsafeUtility.GetUnsafePtr(radianceBuffer); @@ -121,16 +133,18 @@ public unsafe IProbeIntegrator.Result IntegrateIndirectRadiance(IDeviceContext c const bool ignoreDirectEnvironment = false; int giSampleCount = sampleCount; int envSampleCount = ignoreIndirectEnvironment ? 0 : sampleCount; - var lightBakerResult = LightBaker.IntegrateProbeIndirectRadianceWintermute(positionsPtr, _integrationContext, positionOffset, positionCount, _pushoff, + var lightBakerResult = LightBaker.IntegrateProbeIndirectRadianceWintermute(positionsPtr, _integrationContext, positionCount, _pushoff, _bounceCount, directSampleCount, giSampleCount, envSampleCount, ignoreDirectEnvironment, ignoreIndirectEnvironment, wmContext, _progress, shPtr); // TODO: Fix this in LIGHT-1479, synchronization and read-back should be done by the user. if (lightBakerResult.type != LightBaker.ResultType.Success) return lightBakerResult.ConvertToIProbeIntegratorResult(); - eventId = context.WriteBuffer(radianceEstimateOut, radianceBuffer); + eventId = context.CreateEvent(); + context.WriteBuffer(radianceEstimateOut, radianceBuffer, eventId); waitResult = context.Wait(eventId); Debug.Assert(waitResult, "Failed to write radiance to context."); + context.DestroyEvent(eventId); if (!waitResult) lightBakerResult = new LightBaker.Result {type = LightBaker.ResultType.IOFailed, message = "Failed to write radiance to context."}; @@ -142,30 +156,84 @@ public unsafe IProbeIntegrator.Result IntegrateValidity(IDeviceContext context, Debug.Assert(context is WintermuteContext, "Expected RadeonRaysContext but got something else."); var wmContext = context as WintermuteContext; using var positions = new NativeArray(positionCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); - EventID eventId = context.ReadBuffer(_positions, positions); + BufferSlice offsetPositions = _positions; + offsetPositions.Offset += (ulong)positionOffset; + EventID eventId = context.CreateEvent(); + context.ReadBuffer(offsetPositions, positions, eventId); bool waitResult = context.Wait(eventId); Debug.Assert(waitResult, "Failed to read positions from context."); + context.DestroyEvent(eventId); void* positionsPtr = NativeArrayUnsafeUtility.GetUnsafePtr(positions); using var validityBuffer = new NativeArray(positionCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); void* validityPtr = NativeArrayUnsafeUtility.GetUnsafePtr(validityBuffer); int directSampleCount = 0; int giSampleCount = sampleCount; int envSampleCount = 0; - var lightBakerResult = LightBaker.IntegrateProbeValidityWintermute(positionsPtr, _integrationContext, positionOffset, positionCount, _pushoff, + var lightBakerResult = LightBaker.IntegrateProbeValidityWintermute(positionsPtr, _integrationContext, positionCount, _pushoff, _bounceCount, directSampleCount, giSampleCount, envSampleCount, wmContext, _progress, validityPtr); // TODO: Fix this in LIGHT-1479, synchronization and read-back should be done by the user. if (lightBakerResult.type != LightBaker.ResultType.Success) return lightBakerResult.ConvertToIProbeIntegratorResult(); - eventId = context.WriteBuffer(validityEstimateOut, validityBuffer); + eventId = context.CreateEvent(); + context.WriteBuffer(validityEstimateOut, validityBuffer, eventId); waitResult = context.Wait(eventId); Debug.Assert(waitResult, "Failed to write validity to context."); + context.DestroyEvent(eventId); if (!waitResult) lightBakerResult = new LightBaker.Result {type = LightBaker.ResultType.IOFailed, message = "Failed to write validity to context."}; return lightBakerResult.ConvertToIProbeIntegratorResult(); } + + public unsafe IProbeIntegrator.Result IntegrateOcclusion(IDeviceContext context, int positionOffset, int positionCount, int sampleCount, + int maxLightsPerProbe, BufferSlice perProbeLightIndices, BufferSlice probeOcclusionEstimateOut) + { + Debug.Assert(context is WintermuteContext, "Expected RadeonRaysContext but got something else."); + var wmContext = context as WintermuteContext; + Debug.Assert(maxLightsPerProbe == 4, "WintermuteProbeIntegrator only supports 4 light per probe."); + using var positions = new NativeArray(positionCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); + BufferSlice offsetPositions = _positions; + offsetPositions.Offset += (ulong)positionOffset; + EventID eventId = context.CreateEvent(); + context.ReadBuffer(offsetPositions, positions, eventId); + bool waitResult = context.Wait(eventId); + Debug.Assert(waitResult, "Failed to read positions from context."); + context.DestroyEvent(eventId); + void* positionsPtr = NativeArrayUnsafeUtility.GetUnsafePtr(positions); + + using var perProbeLightIndicesArray = new NativeArray(positionCount * 4, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); + eventId = context.CreateEvent(); + context.ReadBuffer(perProbeLightIndices, perProbeLightIndicesArray, eventId); + waitResult = context.Wait(eventId); + Debug.Assert(waitResult, "Failed to read indices from context."); + context.DestroyEvent(eventId); + void* perProbeLightIndicesPtr = NativeArrayUnsafeUtility.GetUnsafePtr(perProbeLightIndicesArray); + + using var occlusionBuffer = new NativeArray(positionCount * maxLightsPerProbe, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); + void* occlusionPtr = NativeArrayUnsafeUtility.GetUnsafePtr(occlusionBuffer); + int directSampleCount = sampleCount; + int giSampleCount = 0; + int envSampleCount = 0; + var lightBakerResult = LightBaker.IntegrateProbeOcclusionWintermute(positionsPtr, perProbeLightIndicesPtr, positionCount, + _pushoff, _bounceCount, directSampleCount, giSampleCount, envSampleCount, wmContext, _progress, occlusionPtr); + + // TODO: Fix this in LIGHT-1479, synchronization and read-back should be done by the user. + if (lightBakerResult.type != LightBaker.ResultType.Success) + return lightBakerResult.ConvertToIProbeIntegratorResult(); + + eventId = context.CreateEvent(); + context.WriteBuffer(probeOcclusionEstimateOut, occlusionBuffer, eventId); + waitResult = context.Wait(eventId); + Debug.Assert(waitResult, "Failed to write validity to context."); + context.DestroyEvent(eventId); + if (!waitResult) + lightBakerResult = new LightBaker.Result { type = LightBaker.ResultType.IOFailed, message = "Failed to write validity to context." }; + + return lightBakerResult.ConvertToIProbeIntegratorResult(); + } + public void Dispose() { } @@ -199,9 +267,13 @@ public unsafe IProbeIntegrator.Result IntegrateDirectRadiance(IDeviceContext con Debug.Assert(context is RadeonRaysContext, "Expected RadeonRaysContext but got something else."); var rrContext = context as RadeonRaysContext; using var positions = new NativeArray(positionCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); - EventID eventId = context.ReadBuffer(_positions, positions); + BufferSlice offsetPositions = _positions; + offsetPositions.Offset += (ulong)positionOffset; + EventID eventId = context.CreateEvent(); + context.ReadBuffer(offsetPositions, positions, eventId); bool waitResult = context.Wait(eventId); Debug.Assert(waitResult, "Failed to read positions from context."); + context.DestroyEvent(eventId); UnityEngine.Vector3* positionsPtr = (Vector3*)NativeArrayUnsafeUtility.GetUnsafePtr(positions); using var radianceBuffer = new NativeArray(positionCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); void* shPtr = NativeArrayUnsafeUtility.GetUnsafePtr(radianceBuffer); @@ -209,16 +281,18 @@ public unsafe IProbeIntegrator.Result IntegrateDirectRadiance(IDeviceContext con int giSampleCount = 0; int envSampleCount = 0; const bool ignoreIndirectEnvironment = true; - var lightBakerResult = LightBaker.IntegrateProbeDirectRadianceRadeonRays(positionsPtr, _integrationContext, positionOffset, positionCount, _pushoff, + var lightBakerResult = LightBaker.IntegrateProbeDirectRadianceRadeonRays(positionsPtr, _integrationContext, positionCount, _pushoff, _bounceCount, directSampleCount, giSampleCount, envSampleCount, ignoreDirectEnvironment, ignoreIndirectEnvironment, rrContext, _progress, shPtr); // TODO: Fix this in LIGHT-1479, synchronization and read-back should be done by the user. if (lightBakerResult.type != LightBaker.ResultType.Success) return lightBakerResult.ConvertToIProbeIntegratorResult(); - eventId = context.WriteBuffer(radianceEstimateOut, radianceBuffer); + eventId = context.CreateEvent(); + context.WriteBuffer(radianceEstimateOut, radianceBuffer, eventId); waitResult = context.Wait(eventId); Debug.Assert(waitResult, "Failed to write radiance to context."); + context.DestroyEvent(eventId); if (!waitResult) lightBakerResult = new LightBaker.Result {type = LightBaker.ResultType.IOFailed, message = "Failed to write radiance to context."}; @@ -231,9 +305,13 @@ public unsafe IProbeIntegrator.Result IntegrateIndirectRadiance(IDeviceContext c Debug.Assert(context is RadeonRaysContext, "Expected RadeonRaysContext but got something else."); var rrContext = context as RadeonRaysContext; using var positions = new NativeArray(positionCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); - EventID eventId = context.ReadBuffer(_positions, positions); + BufferSlice offsetPositions = _positions; + offsetPositions.Offset += (ulong)positionOffset; + EventID eventId = context.CreateEvent(); + context.ReadBuffer(offsetPositions, positions, eventId); bool waitResult = context.Wait(eventId); Debug.Assert(waitResult, "Failed to read positions from context."); + context.DestroyEvent(eventId); UnityEngine.Vector3* positionsPtr = (Vector3*)NativeArrayUnsafeUtility.GetUnsafePtr(positions); using var radianceBuffer = new NativeArray(positionCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); void* shPtr = NativeArrayUnsafeUtility.GetUnsafePtr(radianceBuffer); @@ -241,16 +319,18 @@ public unsafe IProbeIntegrator.Result IntegrateIndirectRadiance(IDeviceContext c const bool ignoreDirectEnvironment = false; int giSampleCount = sampleCount; int envSampleCount = ignoreIndirectEnvironment ? 0 : sampleCount; - var lightBakerResult = LightBaker.IntegrateProbeIndirectRadianceRadeonRays(positionsPtr, _integrationContext, positionOffset, positionCount, _pushoff, + var lightBakerResult = LightBaker.IntegrateProbeIndirectRadianceRadeonRays(positionsPtr, _integrationContext, positionCount, _pushoff, _bounceCount, directSampleCount, giSampleCount, envSampleCount, ignoreDirectEnvironment, ignoreIndirectEnvironment, rrContext, _progress, shPtr); // TODO: Fix this in LIGHT-1479, synchronization and read-back should be done by the user. if (lightBakerResult.type != LightBaker.ResultType.Success) return lightBakerResult.ConvertToIProbeIntegratorResult(); - eventId = context.WriteBuffer(radianceEstimateOut, radianceBuffer); + eventId = context.CreateEvent(); + context.WriteBuffer(radianceEstimateOut, radianceBuffer, eventId); waitResult = context.Wait(eventId); Debug.Assert(waitResult, "Failed to write radiance to context."); + context.DestroyEvent(eventId); if (!waitResult) lightBakerResult = new LightBaker.Result {type = LightBaker.ResultType.IOFailed, message = "Failed to write radiance to context."}; @@ -262,30 +342,84 @@ public unsafe IProbeIntegrator.Result IntegrateValidity(IDeviceContext context, Debug.Assert(context is RadeonRaysContext, "Expected RadeonRaysContext but got something else."); var rrContext = context as RadeonRaysContext; using var positions = new NativeArray(positionCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); - EventID eventId = context.ReadBuffer(_positions, positions); + BufferSlice offsetPositions = _positions; + offsetPositions.Offset += (ulong)positionOffset; + EventID eventId = context.CreateEvent(); + context.ReadBuffer(offsetPositions, positions, eventId); bool waitResult = context.Wait(eventId); Debug.Assert(waitResult, "Failed to read positions from context."); + context.DestroyEvent(eventId); void* positionsPtr = NativeArrayUnsafeUtility.GetUnsafePtr(positions); using var validityBuffer = new NativeArray(positionCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); void* validityPtr = NativeArrayUnsafeUtility.GetUnsafePtr(validityBuffer); int directSampleCount = 0; int giSampleCount = sampleCount; int envSampleCount = 0; - var lightBakerResult = LightBaker.IntegrateProbeValidityRadeonRays(positionsPtr, _integrationContext, positionOffset, positionCount, _pushoff, + var lightBakerResult = LightBaker.IntegrateProbeValidityRadeonRays(positionsPtr, _integrationContext, positionCount, _pushoff, _bounceCount, directSampleCount, giSampleCount, envSampleCount, rrContext, _progress, validityPtr); // TODO: Fix this in LIGHT-1479, synchronization and read-back should be done by the user. if (lightBakerResult.type != LightBaker.ResultType.Success) return lightBakerResult.ConvertToIProbeIntegratorResult(); - eventId = context.WriteBuffer(validityEstimateOut, validityBuffer); + eventId = context.CreateEvent(); + context.WriteBuffer(validityEstimateOut, validityBuffer, eventId); waitResult = context.Wait(eventId); Debug.Assert(waitResult, "Failed to write validity to context."); + context.DestroyEvent(eventId); if (!waitResult) lightBakerResult = new LightBaker.Result {type = LightBaker.ResultType.IOFailed, message = "Failed to write validity to context."}; return lightBakerResult.ConvertToIProbeIntegratorResult(); } + + public unsafe IProbeIntegrator.Result IntegrateOcclusion(IDeviceContext context, int positionOffset, int positionCount, int sampleCount, + int maxLightsPerProbe, BufferSlice perProbeLightIndices, BufferSlice probeOcclusionEstimateOut) + { + Debug.Assert(context is RadeonRaysContext, "Expected RadeonRaysContext but got something else."); + var rrContext = context as RadeonRaysContext; + Debug.Assert(maxLightsPerProbe == 4, "RadeonRaysProbeIntegrator only supports 4 light per probe."); + using var positions = new NativeArray(positionCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); + BufferSlice offsetPositions = _positions; + offsetPositions.Offset += (ulong)positionOffset; + EventID eventId = context.CreateEvent(); + context.ReadBuffer(offsetPositions, positions, eventId); + bool waitResult = context.Wait(eventId); + Debug.Assert(waitResult, "Failed to read positions from context."); + context.DestroyEvent(eventId); + void* positionsPtr = NativeArrayUnsafeUtility.GetUnsafePtr(positions); + + using var perProbeLightIndicesArray = new NativeArray(positionCount * 4, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); + eventId = context.CreateEvent(); + context.ReadBuffer(perProbeLightIndices, perProbeLightIndicesArray, eventId); + waitResult = context.Wait(eventId); + Debug.Assert(waitResult, "Failed to read indices from context."); + context.DestroyEvent(eventId); + void* perProbeLightIndicesPtr = NativeArrayUnsafeUtility.GetUnsafePtr(perProbeLightIndicesArray); + + using var occlusionBuffer = new NativeArray(positionCount * maxLightsPerProbe, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); + void* occlusionPtr = NativeArrayUnsafeUtility.GetUnsafePtr(occlusionBuffer); + int directSampleCount = sampleCount; + int giSampleCount = 0; + int envSampleCount = 0; + var lightBakerResult = LightBaker.IntegrateProbeOcclusionRadeonRays(positionsPtr, perProbeLightIndicesPtr, positionCount, + _pushoff, _bounceCount, directSampleCount, giSampleCount, envSampleCount, rrContext, _progress, occlusionPtr); + + if (lightBakerResult.type != LightBaker.ResultType.Success) + return lightBakerResult.ConvertToIProbeIntegratorResult(); + + eventId = context.CreateEvent(); + context.WriteBuffer(probeOcclusionEstimateOut, occlusionBuffer, eventId); + // TODO: Fix this in LIGHT-1479, synchronization and read-back should be done by the user. + waitResult = context.Wait(eventId); + Debug.Assert(waitResult, "Failed to write validity to context."); + context.DestroyEvent(eventId); + if (!waitResult) + lightBakerResult = new LightBaker.Result { type = LightBaker.ResultType.IOFailed, message = "Failed to write validity to context." }; + + return lightBakerResult.ConvertToIProbeIntegratorResult(); + } + public void Dispose() { } diff --git a/Editor/Mono/GI/RadeonRaysDeviceContext.bindings.cs b/Editor/Mono/GI/RadeonRaysDeviceContext.bindings.cs index 3374ea0d58..3f524ccf17 100644 --- a/Editor/Mono/GI/RadeonRaysDeviceContext.bindings.cs +++ b/Editor/Mono/GI/RadeonRaysDeviceContext.bindings.cs @@ -11,7 +11,7 @@ namespace UnityEngine.LightTransport { [StructLayout(LayoutKind.Sequential)] - public class RadeonRaysContext : IDeviceContext, IDisposable + public class RadeonRaysContext : IDeviceContext { internal IntPtr m_Ptr; internal bool m_OwnsPtr; @@ -64,27 +64,49 @@ internal static class BindingsMarshaller public extern void DestroyBuffer(BufferID id); [NativeMethod(IsThreadSafe = true)] - private unsafe extern EventID EnqueueBufferRead(BufferID id, void* result, UInt64 length, UInt64 offset); + private unsafe extern void EnqueueBufferRead(BufferID id, void* result, UInt64 length, UInt64 offset, EventID* eventId); - public unsafe EventID ReadBuffer(BufferSlice src, NativeArray dst) + public unsafe void ReadBuffer(BufferSlice src, NativeArray dst) where T: struct { void* ptr = NativeArrayUnsafeUtility.GetUnsafePtr(dst); UInt64 sizeofElem = (UInt64)UnsafeUtility.SizeOf(); - return EnqueueBufferRead(src.Id, ptr, (UInt64)dst.Length * sizeofElem, src.Offset * sizeofElem); + EnqueueBufferRead(src.Id, ptr, (UInt64)dst.Length * sizeofElem, src.Offset * sizeofElem, null); + } + + public unsafe void ReadBuffer(BufferSlice src, NativeArray dst, EventID id) + where T : struct + { + void* ptr = NativeArrayUnsafeUtility.GetUnsafePtr(dst); + UInt64 sizeofElem = (UInt64)UnsafeUtility.SizeOf(); + EnqueueBufferRead(src.Id, ptr, (UInt64)dst.Length * sizeofElem, src.Offset * sizeofElem, &id); } [NativeMethod(IsThreadSafe = true)] - private extern unsafe EventID EnqueueBufferWrite(BufferID id, void* result, UInt64 length, UInt64 offset); + private extern unsafe void EnqueueBufferWrite(BufferID id, void* result, UInt64 length, UInt64 offset, EventID* eventId); - public unsafe EventID WriteBuffer(BufferSlice dst, NativeArray src) + public unsafe void WriteBuffer(BufferSlice dst, NativeArray src) where T: struct { void* ptr = NativeArrayUnsafeUtility.GetUnsafePtr(src); UInt64 sizeofElem = (UInt64)UnsafeUtility.SizeOf(); - return EnqueueBufferWrite(dst.Id, ptr, (UInt64)src.Length * sizeofElem, dst.Offset * sizeofElem); + EnqueueBufferWrite(dst.Id, ptr, (UInt64)src.Length * sizeofElem, dst.Offset * sizeofElem, null); } + public unsafe void WriteBuffer(BufferSlice dst, NativeArray src, EventID id) + where T : struct + { + void* ptr = NativeArrayUnsafeUtility.GetUnsafePtr(src); + UInt64 sizeofElem = (UInt64)UnsafeUtility.SizeOf(); + EnqueueBufferWrite(dst.Id, ptr, (UInt64)src.Length * sizeofElem, dst.Offset * sizeofElem, &id); + } + + [NativeMethod(IsThreadSafe = true, Name = "CreateEventInternal")] + public extern EventID CreateEvent(); + + [NativeMethod(IsThreadSafe = true)] + public extern void DestroyEvent(EventID id); + [NativeMethod(IsThreadSafe = true)] public extern bool IsCompleted(EventID id); diff --git a/Editor/Mono/GI/RadeonRaysLightBaker.bindings.cs b/Editor/Mono/GI/RadeonRaysLightBaker.bindings.cs index bfd1cae1e2..1b8d4933d8 100644 --- a/Editor/Mono/GI/RadeonRaysLightBaker.bindings.cs +++ b/Editor/Mono/GI/RadeonRaysLightBaker.bindings.cs @@ -15,19 +15,24 @@ internal static extern Result PopulateWorldRadeonRays(BakeInput bakeInput, Unity [NativeMethod(IsThreadSafe = true)] internal static extern unsafe Result IntegrateProbeDirectRadianceRadeonRays(void* positions, UnityEngine.LightTransport.IntegrationContext integrationContext, - int positionOffset, int positionCount, float pushoff, int bounceCount, int directSampleCount, int giSampleCount, int envSampleCount, + int positionCount, float pushoff, int bounceCount, int directSampleCount, int giSampleCount, int envSampleCount, bool ignoreDirectEnvironment, bool ignoreIndirectEnvironment, UnityEngine.LightTransport.RadeonRaysContext context, UnityEngine.LightTransport.BakeProgressState progress, void* radianceBufferOut); [NativeMethod(IsThreadSafe = true)] internal static extern unsafe Result IntegrateProbeIndirectRadianceRadeonRays(void* positions, UnityEngine.LightTransport.IntegrationContext integrationContext, - int positionOffset, int positionCount, float pushoff, int bounceCount, int directSampleCount, int giSampleCount, int envSampleCount, + int positionCount, float pushoff, int bounceCount, int directSampleCount, int giSampleCount, int envSampleCount, bool ignoreDirectEnvironment, bool ignoreIndirectEnvironment, UnityEngine.LightTransport.RadeonRaysContext context, UnityEngine.LightTransport.BakeProgressState progress, void* radianceBufferOut); [NativeMethod(IsThreadSafe = true)] internal static extern unsafe Result IntegrateProbeValidityRadeonRays(void* positions, UnityEngine.LightTransport.IntegrationContext integrationContext, - int positionOffset, int positionCount, float pushoff, int bounceCount, int directSampleCount, int giSampleCount, int envSampleCount, + int positionCount, float pushoff, int bounceCount, int directSampleCount, int giSampleCount, int envSampleCount, UnityEngine.LightTransport.RadeonRaysContext context, UnityEngine.LightTransport.BakeProgressState progress, void* validityBufferOut); + + [NativeMethod(IsThreadSafe = true)] + internal static extern unsafe Result IntegrateProbeOcclusionRadeonRays(void* positions, void* probeLightIndices, + int positionCount, float pushoff, int bounceCount, int directSampleCount, int giSampleCount, int envSampleCount, + UnityEngine.LightTransport.RadeonRaysContext context, UnityEngine.LightTransport.BakeProgressState progress, void* occlusionBufferOut); } } diff --git a/Editor/Mono/GI/WintermuteDeviceContext.bindings.cs b/Editor/Mono/GI/WintermuteDeviceContext.bindings.cs index 1fefda10f9..62bfeb49c7 100644 --- a/Editor/Mono/GI/WintermuteDeviceContext.bindings.cs +++ b/Editor/Mono/GI/WintermuteDeviceContext.bindings.cs @@ -79,22 +79,41 @@ public void DestroyBuffer(BufferID id) buffers.Remove(id); } - public EventID WriteBuffer(BufferSlice dst, NativeArray src) + public void WriteBuffer(BufferSlice dst, NativeArray src) where T : struct { Debug.Assert(buffers.ContainsKey(dst.Id), "Invalid buffer ID given."); var dstBuffer = buffers[dst.Id].Reinterpret(1); dstBuffer.GetSubArray((int)dst.Offset, dstBuffer.Length - (int)dst.Offset).CopyFrom(src); - return new EventID(); } - public EventID ReadBuffer(BufferSlice src, NativeArray dst) + public void ReadBuffer(BufferSlice src, NativeArray dst) where T : struct { Debug.Assert(buffers.ContainsKey(src.Id), "Invalid buffer ID given."); var srcBuffer = buffers[src.Id].Reinterpret(1); dst.CopyFrom(srcBuffer.GetSubArray((int)src.Offset, srcBuffer.Length - (int)src.Offset)); - return new EventID { Value = nextFreeEventId++ }; + } + + public void WriteBuffer(BufferSlice dst, NativeArray src, EventID id) + where T : struct + { + WriteBuffer(dst, src); + } + + public void ReadBuffer(BufferSlice src, NativeArray dst, EventID id) + where T : struct + { + ReadBuffer(src, dst); + } + + public EventID CreateEvent() + { + return new EventID(nextFreeEventId++); + } + + public void DestroyEvent(EventID id) + { } public bool IsCompleted(EventID id) diff --git a/Editor/Mono/GI/WintermuteLightBaker.bindings.cs b/Editor/Mono/GI/WintermuteLightBaker.bindings.cs index c092e7fb4f..2e0e0f7586 100644 --- a/Editor/Mono/GI/WintermuteLightBaker.bindings.cs +++ b/Editor/Mono/GI/WintermuteLightBaker.bindings.cs @@ -15,19 +15,24 @@ internal static extern Result PopulateWorldWintermute(BakeInput bakeInput, Unity [NativeMethod(IsThreadSafe = true)] internal static extern unsafe Result IntegrateProbeDirectRadianceWintermute(UnityEngine.Vector3* positions, UnityEngine.LightTransport.IntegrationContext integrationContext, - int positionOffset, int positionCount, float pushoff, int bounceCount, int directSampleCount, int giSampleCount, int envSampleCount, + int positionCount, float pushoff, int bounceCount, int directSampleCount, int giSampleCount, int envSampleCount, bool ignoreDirectEnvironment, bool ignoreIndirectEnvironment, UnityEngine.LightTransport.WintermuteContext context, UnityEngine.LightTransport.BakeProgressState progress, void* radianceBufferOut); [NativeMethod(IsThreadSafe = true)] internal static extern unsafe Result IntegrateProbeIndirectRadianceWintermute(UnityEngine.Vector3* positions, UnityEngine.LightTransport.IntegrationContext integrationContext, - int positionOffset, int positionCount, float pushoff, int bounceCount, int directSampleCount, int giSampleCount, int envSampleCount, + int positionCount, float pushoff, int bounceCount, int directSampleCount, int giSampleCount, int envSampleCount, bool ignoreDirectEnvironment, bool ignoreIndirectEnvironment, UnityEngine.LightTransport.WintermuteContext context, UnityEngine.LightTransport.BakeProgressState progress, void* radianceBufferOut); [NativeMethod(IsThreadSafe = true)] internal static extern unsafe Result IntegrateProbeValidityWintermute(void* positions, UnityEngine.LightTransport.IntegrationContext integrationContext, - int positionOffset, int positionCount, float pushoff, int bounceCount, int directSampleCount, int giSampleCount, int envSampleCount, + int positionCount, float pushoff, int bounceCount, int directSampleCount, int giSampleCount, int envSampleCount, UnityEngine.LightTransport.WintermuteContext context, UnityEngine.LightTransport.BakeProgressState progress, void* validityBufferOut); + + [NativeMethod(IsThreadSafe = true)] + internal static extern unsafe Result IntegrateProbeOcclusionWintermute(void* positions, void* probeLightIndices, + int positionCount, float pushoff, int bounceCount, int directSampleCount, int giSampleCount, int envSampleCount, + UnityEngine.LightTransport.WintermuteContext context, UnityEngine.LightTransport.BakeProgressState progress, void* occlusionBufferOut); } } diff --git a/Editor/Mono/GUI/DockArea.cs b/Editor/Mono/GUI/DockArea.cs index 06434192be..93f1f7f0fa 100644 --- a/Editor/Mono/GUI/DockArea.cs +++ b/Editor/Mono/GUI/DockArea.cs @@ -254,7 +254,7 @@ private static void UpdateWindowTitle(EditorWindow w) if (w && w.m_Parent && w.m_Parent.window && - !w.m_Parent.window.m_IsMppmCloneWindow && + !w.m_Parent.window.IsMultiplayerClone() && w.titleContent != null) { w.m_Parent.window.title = w.titleContent.text; @@ -421,10 +421,6 @@ private void DrawTabs(Rect tabAreaRect) tabStyle = Styles.dragTab; var firstTabStyle = Styles.dragTabFirst; - if (s_HasStaticTabsCapability) - { - firstTabStyle = Styles.tabLabel; - } var totalTabWidth = DragTab(tabAreaRect, m_ScrollOffset, tabStyle, firstTabStyle); if (totalTabWidth > 0f) @@ -861,12 +857,9 @@ private float DragTab(Rect tabAreaRect, float scrollOffset, GUIStyle tabStyle, G { case EventType.TouchDown: case EventType.MouseDown: - if (s_HasStaticTabsCapability) - { - break; - } + // Handle double click - if (EditorWindow.focusedWindow != null) + if (EditorWindow.focusedWindow != null && !s_HasStaticTabsCapability) WindowMaximizeStateOnDoubleClick(tabAreaRect); if (GUIUtility.hotControl == 0) { @@ -893,10 +886,7 @@ private float DragTab(Rect tabAreaRect, float scrollOffset, GUIStyle tabStyle, G } break; case EventType.ContextClick: - if (s_HasStaticTabsCapability) - { - break; - } + if (GUIUtility.hotControl == 0) { int sel = GetTabAtMousePos(tabStyle, evt.mousePosition, scrollOffset, tabAreaRect); @@ -910,10 +900,11 @@ private float DragTab(Rect tabAreaRect, float scrollOffset, GUIStyle tabStyle, G case EventType.TouchMove: case EventType.MouseDrag: - if (s_HasStaticTabsCapability) + if (s_HasStaticTabsCapability) { break; } + if (evt.pointerType == PointerType.Pen && !evt.penStatus.HasFlag(PenStatus.Contact)) break; @@ -1018,10 +1009,7 @@ private float DragTab(Rect tabAreaRect, float scrollOffset, GUIStyle tabStyle, G break; case EventType.TouchUp: case EventType.MouseUp: - if (ModeService.HasCapability(ModeCapability.StaticTabs, false)) - { - break; - } + if (GUIUtility.hotControl == id) { Vector2 screenMousePos = GUIUtility.GUIToScreenPoint(evt.mousePosition); diff --git a/Editor/Mono/GUI/PopupWindow.cs b/Editor/Mono/GUI/PopupWindow.cs index 26d03d32fa..920167eeef 100644 --- a/Editor/Mono/GUI/PopupWindow.cs +++ b/Editor/Mono/GUI/PopupWindow.cs @@ -3,6 +3,7 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using UnityEngine; +using UnityEngine.UIElements; namespace UnityEditor { @@ -14,7 +15,9 @@ public abstract class PopupWindowContent { public EditorWindow editorWindow { get; internal set; } - public abstract void OnGUI(Rect rect); + public virtual void OnGUI(Rect rect) { } + public virtual VisualElement CreateGUI() => null; + public virtual Vector2 GetWindowSize() { return new Vector2(200, 200); @@ -26,12 +29,22 @@ public virtual void OnClose() {} public class PopupWindow : EditorWindow { + const string k_UssClassName = "unity-popup-window-root"; + const string k_InvalidSizeTemplate = "Invalid content size: {0}. Specify dimensions greater than zero in CreateGUI."; + + public static readonly string invalidSizeLabelUssClassName = "unity-popup-window__invalid-size-label"; + static readonly Vector2 k_DefaultWindowSize = new(10, 10); + PopupWindowContent m_WindowContent; Vector2 m_LastWantedSize; Rect m_ActivatorRect; PopupLocation[] m_LocationPriorityOrder; static double s_LastClosedTime; static Rect s_LastActivatorRect; + VisualElement m_UserContent; + + bool UseIMGUI => !UseUIToolkit; + bool UseUIToolkit => m_UserContent != null; internal PopupWindow() { @@ -52,18 +65,11 @@ internal static void Show(Rect activatorRect, PopupWindowContent windowContent, { // If we already have a popup window showing this type of content, then just close // the existing one. - var existingWindows = Resources.FindObjectsOfTypeAll(typeof(PopupWindow)); - if (existingWindows != null && existingWindows.Length > 0) + var existingPopup = FindExistingPopupWindow(windowContent); + if (existingPopup != null) { - var existingPopup = existingWindows[0] as PopupWindow; - if (existingPopup != null && existingPopup.m_WindowContent != null && windowContent != null) - { - if (existingPopup.m_WindowContent.GetType() == windowContent.GetType()) - { - existingPopup.CloseWindow(); - return; - } - } + existingPopup.CloseWindow(); + return; } if (ShouldShowWindow(activatorRect)) @@ -103,32 +109,95 @@ internal void Init(Rect activatorRect, PopupWindowContent windowContent, PopupLo m_LastWantedSize = Vector2.zero; m_LocationPriorityOrder = locationPriorityOrder; - ShowAsDropDown(m_ActivatorRect, m_WindowContent.GetWindowSize(), locationPriorityOrder, showMode, giveFocus); + ShowAsDropDown(m_ActivatorRect, k_DefaultWindowSize, locationPriorityOrder, showMode, giveFocus); + + if (UseUIToolkit) + SetupPopupAutoSize(); + else + FitWindowToContent(); } internal void OnGUI() { - FitWindowToContent(); - Rect windowRect = new Rect(0, 0, position.width, position.height); - m_WindowContent.OnGUI(windowRect); - GUI.Label(windowRect, GUIContent.none, "grey_border"); - FitWindowToContent(); + if (UseIMGUI) + { + FitWindowToContent(); + Rect windowRect = new Rect(0, 0, position.width, position.height); + m_WindowContent.OnGUI(windowRect); + GUI.Label(windowRect, GUIContent.none, "grey_border"); + FitWindowToContent(); + } + } + + void CreateGUI() + { + m_UserContent = m_WindowContent?.CreateGUI(); + if (m_UserContent != null) + { + var infiniteCanvas = new VisualElement { style = { position = Position.Absolute } }; + infiniteCanvas.AddToClassList(k_UssClassName); + rootVisualElement.Add(infiniteCanvas); + infiniteCanvas.Add(m_UserContent); + } } - private void FitWindowToContent() + void FitWindowToContent() { if (m_WindowContent == null) return; Vector2 wantedSize = m_WindowContent.GetWindowSize(); - if (m_LastWantedSize != wantedSize) + SetWindowSize(wantedSize); + } + + void SetWindowSize(Vector2 size) + { + if (this && m_LastWantedSize != size) { - m_LastWantedSize = wantedSize; - Rect screenRect = m_Parent.window.GetDropDownRect(m_ActivatorRect, wantedSize, wantedSize, m_LocationPriorityOrder); + m_LastWantedSize = size; + Rect screenRect = m_Parent.window.GetDropDownRect(m_ActivatorRect, size, size, m_LocationPriorityOrder); minSize = maxSize = new Vector2(screenRect.width, screenRect.height); position = screenRect; } } + void SetupPopupAutoSize() + { + if (UseUIToolkit && rootVisualElement.panel is Panel panel) + { + panel.ValidateLayout(); + var contentSize = m_UserContent.layout.size; + if (contentSize.x <= 0f || contentSize.y <= 0f) + { + var invalidSizeMessage = string.Format(k_InvalidSizeTemplate, contentSize); + AddInvalidSizeLabel(invalidSizeMessage); + panel.ValidateLayout(); // measure again to get the size of the label + } + + var canvasSize = m_UserContent.parent.layout.size; + SetWindowSize(canvasSize); + m_UserContent.RegisterCallback(OnContentGeometryChanged); + } + } + + void AddInvalidSizeLabel(string text) + { + var invalidSizeMessage = new TextElement + { + text = text, + enableRichText = true + }; + invalidSizeMessage.AddToClassList(invalidSizeLabelUssClassName); + m_UserContent.Add(invalidSizeMessage); + } + + void OnContentGeometryChanged(GeometryChangedEvent evt) + { + var size = evt.newRect.size; + + // Schedule the size change to avoid multiple layout events in the same frame + rootVisualElement.schedule.Execute(() => { SetWindowSize(size); }); + } + void CloseWindow() { Close(); @@ -147,11 +216,29 @@ protected virtual void OnDisable() CloseContent(); } - // Change to private protected once available in C#. - internal void CloseContent() + private protected void CloseContent() + { + m_WindowContent?.OnClose(); + m_UserContent?.UnregisterCallback(OnContentGeometryChanged); + m_UserContent = null; + } + + static PopupWindow FindExistingPopupWindow(PopupWindowContent windowContent) { - if (m_WindowContent != null) - m_WindowContent.OnClose(); + var existingWindows = Resources.FindObjectsOfTypeAll(typeof(PopupWindow)); + if (existingWindows != null && existingWindows.Length > 0) + { + var existingPopup = existingWindows[0] as PopupWindow; + if (existingPopup != null && existingPopup.m_WindowContent != null && windowContent != null) + { + if (existingPopup.m_WindowContent.GetType() == windowContent.GetType()) + { + return existingPopup; + } + } + } + + return null; } } } diff --git a/Editor/Mono/GUI/WindowLayout.cs b/Editor/Mono/GUI/WindowLayout.cs index 6996bbf183..6abfd2ff32 100644 --- a/Editor/Mono/GUI/WindowLayout.cs +++ b/Editor/Mono/GUI/WindowLayout.cs @@ -285,7 +285,6 @@ internal static ContainerWindow ShowWindowWithDynamicLayout(string windowId, str var window = Resources.FindObjectsOfTypeAll().FirstOrDefault(w => w.windowID == windowId); InitContainerWindow(ref window, windowId, layoutData); - window.m_IsMppmCloneWindow = true; GenerateLayout(window, ShowMode.Utility, availableEditorWindowTypes, centerViewInfo, topViewInfo, bottomViewInfo, layoutData); window.m_DontSaveToLayout = !Convert.ToBoolean(layoutData["restore_saved_layout"]); return window; @@ -1771,7 +1770,7 @@ internal static class CreateBuiltinWindows [MenuItem("Window/General/Scene %1", false, 1)] static void ShowSceneView() { - EditorWindow.GetWindow(); + EditorWindow.GetWindowWithExactType(); } [MenuItem("Window/General/Game %2", false, 2)] diff --git a/Editor/Mono/Graphics/GraphicsStateCollectionImporter.cs b/Editor/Mono/Graphics/GraphicsStateCollectionImporter.cs new file mode 100644 index 0000000000..b045182158 --- /dev/null +++ b/Editor/Mono/Graphics/GraphicsStateCollectionImporter.cs @@ -0,0 +1,82 @@ +// 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.AssetImporters; +using UnityEngine.Rendering; +using UnityEngine.Experimental.Rendering; + +namespace UnityEditor.Experimental.Rendering +{ + [ScriptedImporter(version: 1, ext: "graphicsstate")] + [ExcludeFromPreset] + class GraphicsStateCollectionImporter : ScriptedImporter + { + public RuntimePlatform runtimePlatform; + public GraphicsDeviceType graphicsDeviceType; + public int version; + public string qualityLevelName; + public int shaderVariantCount; + public int graphicsStateCount; + + public override void OnImportAsset(AssetImportContext ctx) + { + GraphicsStateCollection asset = new GraphicsStateCollection(ctx.assetPath); + Texture2D icon = EditorGUIUtility.FindTexture(typeof(DefaultAsset)); + ctx.AddObjectToAsset("graphicsstatecollection", asset, icon); + ctx.SetMainObject(asset); + + // Gather information about collection to display in inspector + runtimePlatform = asset.runtimePlatform; + graphicsDeviceType = asset.graphicsDeviceType; + version = asset.version; + qualityLevelName = asset.qualityLevelName; + shaderVariantCount = asset.variantCount; + graphicsStateCount = asset.totalGraphicsStateCount; + } + } + + [CustomEditor(typeof(GraphicsStateCollectionImporter))] + class GraphicsStateCollectionImporterEditor : ScriptedImporterEditor + { + SerializedProperty m_RuntimePlatform; + SerializedProperty m_GraphicsDeviceType; + SerializedProperty m_Version; + SerializedProperty m_QualityLevelName; + SerializedProperty m_ShaderVariantCount; + SerializedProperty m_GraphicsStateCount; + + public override bool showImportedObject => false; + protected override bool needsApplyRevert => false; + + public override void OnEnable() + { + base.OnEnable(); + + m_RuntimePlatform = serializedObject.FindProperty("runtimePlatform"); + m_GraphicsDeviceType = serializedObject.FindProperty("graphicsDeviceType"); + m_Version = serializedObject.FindProperty("version"); + m_QualityLevelName = serializedObject.FindProperty("qualityLevelName"); + m_ShaderVariantCount = serializedObject.FindProperty("shaderVariantCount"); + m_GraphicsStateCount = serializedObject.FindProperty("graphicsStateCount"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + using (new EditorGUI.DisabledScope(true)) + { + EditorGUILayout.PropertyField(m_RuntimePlatform); + EditorGUILayout.PropertyField(m_GraphicsDeviceType); + EditorGUILayout.PropertyField(m_Version); + EditorGUILayout.PropertyField(m_QualityLevelName, new GUIContent("Quality Level")); + EditorGUILayout.PropertyField(m_ShaderVariantCount); + EditorGUILayout.PropertyField(m_GraphicsStateCount); + } + + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Editor/Mono/IBuildTarget.cs b/Editor/Mono/IBuildTarget.cs index cf0647cf4a..09183a6ad4 100644 --- a/Editor/Mono/IBuildTarget.cs +++ b/Editor/Mono/IBuildTarget.cs @@ -21,6 +21,9 @@ internal interface IBuildTarget // use of this property. string TargetName { get; } + // This property is the unique identifier for the BuildTarget. This should be used for any access identification and serilization. + GUID Guid { get; } + // This property is used as a suffix for il2cpp profiles. Should a more suited place for it exist, move it string RootSystemType { get; } diff --git a/Editor/Mono/IGraphicsPlatformProperties.cs b/Editor/Mono/IGraphicsPlatformProperties.cs index 1b3a74d7f9..4ef57827db 100644 --- a/Editor/Mono/IGraphicsPlatformProperties.cs +++ b/Editor/Mono/IGraphicsPlatformProperties.cs @@ -25,4 +25,10 @@ internal interface IGraphicsPlatformProperties : IPlatformProperties // The PlayerSettingsEditor.OtherSectionRenderingGUI method uses this property to determine whether or not to display unsupportedMSAAFallback bool HasUnsupportedMSAAFallback => false; + + // The PlayerSettingsEditor.OtherSectionRenderingGUI method uses this property to determine whether or not to display colorGamut + bool SupportsColorGamut => false; + + // The PlayerSettings.ResolutionSectionGUI method uses this property to determine whether or not to display retina support + bool RetinaSupport => false; } diff --git a/Editor/Mono/ImportSettings/DesktopPluginImporterExtension.cs b/Editor/Mono/ImportSettings/DesktopPluginImporterExtension.cs index dbfd467b78..5dff00afcd 100644 --- a/Editor/Mono/ImportSettings/DesktopPluginImporterExtension.cs +++ b/Editor/Mono/ImportSettings/DesktopPluginImporterExtension.cs @@ -204,7 +204,7 @@ private bool IsUsableOnOSX(PluginImporter imp) return true; string ext = FileUtil.GetPathExtension(imp.assetPath).ToLower(); - return ext == "bundle" || ext == "dylib" || IsLinuxLibrary(imp.assetPath) || IsCppPluginFile(imp.assetPath); + return ext == "bundle" || ext == "dylib" || ext == "xcprivacy" || IsLinuxLibrary(imp.assetPath) || IsCppPluginFile(imp.assetPath); } private bool IsUsableOnLinux(PluginImporter imp) diff --git a/Editor/Mono/ImportSettings/TextureImporterInspector.cs b/Editor/Mono/ImportSettings/TextureImporterInspector.cs index 2c7045c294..cfe69a8589 100644 --- a/Editor/Mono/ImportSettings/TextureImporterInspector.cs +++ b/Editor/Mono/ImportSettings/TextureImporterInspector.cs @@ -278,7 +278,7 @@ internal class Styles public readonly GUIContent useMipmapLimits = EditorGUIUtility.TrTextContent("Mipmap Limit", "Disable this if the number of mipmap levels to upload should not be limited by the quality settings. (effectively: always upload at full resolution, regardless of the global mipmap limit or mipmap limit groups)"); public readonly GUIContent mipmapLimitGroupName = EditorGUIUtility.TrTextContent("Mipmap Limit Group", "Select a Mipmap Limit Group for this texture. If you do not add this texture to a Mipmap Limit Group, or Unity cannot find the group name you provide, Unity limits the number of mipmap levels it uploads to the maximum defined by the Global Texture Mipmap Limit (see Quality Settings). If Unity can find the Mipmap Limit Group you specify, it respects that group's limit."); public readonly GUIContent mipmapLimitGroupWarning = EditorGUIUtility.TrTextContent("This texture takes the default mipmap limit settings because Unity cannot find the mipmap limit group you have designated. Consult your project's Quality Settings for a list of mipmap limit groups."); - public readonly GUIContent streamingMipmaps = EditorGUIUtility.TrTextContent("Stream Mipmap Levels", "Only load larger mipmap levels as needed to render the current game cameras. Requires Texture Mipmap Streamer to be enabled in quality settings."); + public readonly GUIContent streamingMipmaps = EditorGUIUtility.TrTextContent("Stream Mipmap Levels", "Only load larger mipmap levels as needed to render the current game cameras. Requires Texture Mipmap Streaming to be enabled in quality settings."); public readonly GUIContent streamingMipmapsPriority = EditorGUIUtility.TrTextContent("Priority", "Mipmap streaming priority when there's contention for resources. Positive numbers represent higher priority. Valid range is -128 to 127."); public readonly GUIContent vtOnly = EditorGUIUtility.TrTextContent("Virtual Texture Only", "Texture is optimized for use as a virtual texture and can only be used as a virtual texture."); diff --git a/Editor/Mono/Inspector/AnimationClipEditor.cs b/Editor/Mono/Inspector/AnimationClipEditor.cs index 31f53787fd..0d1b29d3d8 100644 --- a/Editor/Mono/Inspector/AnimationClipEditor.cs +++ b/Editor/Mono/Inspector/AnimationClipEditor.cs @@ -1584,6 +1584,14 @@ private void MuscleClipGUI() CurveGUI(); } + if(m_ClipInfo != null && m_ClipInfo.hasAdditiveReferencePose && m_ClipInfo.GetCurveCount() > 0 && + (m_ClipInfo.additiveReferencePoseFrame < m_ClipInfo.firstFrame || m_ClipInfo.additiveReferencePoseFrame > m_ClipInfo.lastFrame)) + { + EditorGUILayout.HelpBox("Additional curves will be compared to zero values instead of the source clip's curves. "+ + "This is because the source clip doesn't include these specific curves. " + + "To ensure accurate comparisons, consider using a reference pose frame within the clip's start and end frames.", MessageType.Warning); + } + if (m_ClipInfo != null) { wasChanged = GUI.changed; diff --git a/Editor/Mono/Inspector/CameraEditor.cs b/Editor/Mono/Inspector/CameraEditor.cs index 0c383608ec..ea6d773338 100644 --- a/Editor/Mono/Inspector/CameraEditor.cs +++ b/Editor/Mono/Inspector/CameraEditor.cs @@ -62,7 +62,7 @@ internal static class Styles public static readonly GUIContent deferredMSAAWarning = EditorGUIUtility.TrTextContent("The target texture is using MSAA. Note that this will not affect MSAA behaviour of this camera. MSAA rendering for cameras is configured through the 'MSAA' camera setting and related project settings. The target texture will always contain resolved pixel data."); public static readonly GUIContent dynamicResolutionTimingWarning = EditorGUIUtility.TrTextContent("It is recommended to enable Frame Timing Statistics under Rendering Player Settings when using dynamic resolution cameras."); - public static readonly GUIStyle invisibleButton = "InvisibleButton"; + public static GUIStyle invisibleButton; public const string k_CameraEditorUxmlPath = "UXML/InspectorWindow/CameraEditor.uxml"; @@ -767,6 +767,7 @@ void CommandBufferGUI() rowRect.xMax = minusRect.x; GUI.Label(rowRect, string.Format("{0}: {1} ({2})", ce, cb.name, EditorUtility.FormatBytes(cb.sizeInBytes)), EditorStyles.miniLabel); // and a button to remove it + Styles.invisibleButton ??= new GUIStyle("InvisibleButton"); if (GUI.Button(minusRect, Styles.iconRemove, Styles.invisibleButton)) { camera.RemoveCommandBuffer(ce, cb); diff --git a/Editor/Mono/Inspector/Core/InspectorWindow.cs b/Editor/Mono/Inspector/Core/InspectorWindow.cs index 9b9d65cab2..dfb2b2c5eb 100644 --- a/Editor/Mono/Inspector/Core/InspectorWindow.cs +++ b/Editor/Mono/Inspector/Core/InspectorWindow.cs @@ -88,6 +88,7 @@ protected override void OnEnable() m_Tracker.dataMode = GetDataModeController_Internal().dataMode; EditorApplication.projectWasLoaded += OnProjectWasLoaded; + EditorApplication.playModeStateChanged += OnPlayModeStateChanged; Selection.selectionChanged += OnSelectionChanged; AssemblyReloadEvents.afterAssemblyReload += OnAfterAssemblyReload; } @@ -108,6 +109,15 @@ private void OnAfterAssemblyReload() tracker.ForceRebuild(); } + void OnPlayModeStateChanged(PlayModeStateChange state) + { + // Case UUM-64580: unable to interact with the inspector after exiting play mode. + // Somehow the inspector is still showing the last selected object, but the tracker does not respond anymore. + // Forcing a rebuild of the tracker after exiting play mode ensures that it is put back in a valid state. + if (state == PlayModeStateChange.EnteredEditMode) + tracker.ForceRebuild(); + } + void OnBecameVisible() { SceneView.SetActiveEditorsDirty(true); @@ -176,6 +186,7 @@ protected override void OnDisable() m_LockTracker?.lockStateChanged.RemoveListener(LockStateChanged); EditorApplication.projectWasLoaded -= OnProjectWasLoaded; + EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; Selection.selectionChanged -= OnSelectionChanged; AssemblyReloadEvents.afterAssemblyReload -= OnAfterAssemblyReload; } @@ -341,36 +352,60 @@ protected override void EndDrawPreviewAndLabels(Event evt, Rect rect, Rect dragR protected override void CreatePreviewEllipsisMenu(InspectorPreviewWindow window, PropertyEditor editor) { - if (editor.previewWindow != null) - { - window.ClearEllipsisMenu(); - window.AppendActionToEllipsisMenu( - "Convert to Floating Window", - (e) => + if (editor.previewWindow == null) + return; + + var draglineAnchor = m_SplitView.Q(s_draglineAnchor); + var previewContainer = m_SplitView.Q(s_PreviewContainer); + + window.ClearEllipsisMenu(); + window.AppendActionToEllipsisMenu( + "Convert to Floating Window", + (e) => + { + if (m_PreviewWindow == null) { - if (m_PreviewWindow == null) - { - DetachPreview(false); - hasFloatingPreviewWindow = true; - window.parent.Remove(window); - } - else - { - hasFloatingPreviewWindow = false; - m_PreviewWindow.Close(); - } - }, - a => hasFloatingPreviewWindow ? DropdownMenuAction.Status.Checked : DropdownMenuAction.Status.Normal); + PopupPreviewWindow(window); - window.AppendActionToEllipsisMenu( - "Minimize in Inspector", - (e) => + previewContainer.style.display = DisplayStyle.None; + draglineAnchor.style.display = DisplayStyle.None; + } + else { - editor.ExpandCollapsePreview(); - }, - a => !editor.showingPreview ? DropdownMenuAction.Status.Checked : DropdownMenuAction.Status.Normal - ); - } + hasFloatingPreviewWindow = false; + m_PreviewWindow.Close(); + + previewContainer.style.display = DisplayStyle.Flex; + draglineAnchor.style.display = DisplayStyle.Flex; + } + }, + a => hasFloatingPreviewWindow ? DropdownMenuAction.Status.Checked : DropdownMenuAction.Status.Normal); + + window.AppendActionToEllipsisMenu( + "Minimize in Inspector", + (e) => + { + editor.ExpandCollapsePreview(); + }, + a => !editor.showingPreview ? DropdownMenuAction.Status.Checked : DropdownMenuAction.Status.Normal + ); + + draglineAnchor.RegisterCallback(OnDraglineChange, window); + } + + void OnDraglineChange(PointerUpEvent evt, InspectorPreviewWindow window) + { + if (m_PreviewWindow != null || evt.button != (int)MouseButton.RightMouse) + return; + + PopupPreviewWindow(window); + } + + void PopupPreviewWindow(InspectorPreviewWindow window) + { + DetachPreview(false); + hasFloatingPreviewWindow = true; + window.parent.Remove(window); } private void DetachPreview(bool exitGUI = true) diff --git a/Editor/Mono/Inspector/Core/PropertyEditor.cs b/Editor/Mono/Inspector/Core/PropertyEditor.cs index 8aa9d0185e..fcca0cfc72 100644 --- a/Editor/Mono/Inspector/Core/PropertyEditor.cs +++ b/Editor/Mono/Inspector/Core/PropertyEditor.cs @@ -1179,12 +1179,16 @@ internal virtual void RebuildContentsContainers() preview.style.minHeight = m_PreviewMinHeight; previewItem = m_cachedPreviewEditor.CreatePreview(previewWindow); + var draglineAnchor = m_SplitView.Q(s_draglineAnchor); if (previewItem != null) { // Temporary naming while in transition to UITK InitUITKPreview(); preview.Add(previewWindow); + + preview.style.display = DisplayStyle.Flex; + draglineAnchor.style.display = DisplayStyle.Flex; } else // IMGUI fallback if no UITK preview found { @@ -1193,9 +1197,13 @@ internal virtual void RebuildContentsContainers() m_PreviewResizer.SetContainer(previewAndLabelsContainer, kBottomToolbarHeight); previewAndLabelElement.Add(previewAndLabelsContainer); + preview.style.display = DisplayStyle.None; + draglineAnchor.style.display = DisplayStyle.None; + if (preview == null) m_SplitView.Add(previewAndLabelElement); } + } } @@ -1300,8 +1308,6 @@ private void OnDraglineGeometryChange(VisualElement window, VisualElement dragli internal void PrepareToolbar(InspectorPreviewWindow toolbar, bool isFloatingPreviewWindow = false) { - IPreviewable previewEditor = GetEditorThatControlsPreview(tracker.activeEditors); - if(!isFloatingPreviewWindow) CreatePreviewEllipsisMenu(toolbar, this); } @@ -1364,7 +1370,6 @@ internal void ExpandCollapsePreview() { m_CachedPreviewHeight = m_SplitView.fixedPane.resolvedStyle.height; UpdatePreviewHeight(m_PreviewMinHeight); - m_CachedPreviewHeight = m_PreviewMinHeight; } else { @@ -1597,7 +1602,7 @@ private Object[] GetInspectedAssets() protected virtual void EndDrawPreviewAndLabels(Event evt, Rect rect, Rect dragRect) {} protected virtual void CreatePreviewEllipsisMenu(InspectorPreviewWindow window, PropertyEditor editor) {} - TwoPaneSplitView m_SplitView = null; + protected TwoPaneSplitView m_SplitView = null; VisualElement preview = null; internal InspectorPreviewWindow previewWindow = null; private void DrawPreviewAndLabels() diff --git a/Editor/Mono/Inspector/Core/ScriptAttributeGUI/PropertyHandler.cs b/Editor/Mono/Inspector/Core/ScriptAttributeGUI/PropertyHandler.cs index 0661cdf19a..11b22caf7e 100644 --- a/Editor/Mono/Inspector/Core/ScriptAttributeGUI/PropertyHandler.cs +++ b/Editor/Mono/Inspector/Core/ScriptAttributeGUI/PropertyHandler.cs @@ -9,12 +9,16 @@ using UnityEngine; using UnityEditorInternal; using UnityEngine.Bindings; +using Object = UnityEngine.Object; +using UnityEngine.Pool; namespace UnityEditor { [VisibleToOtherModules("UnityEditor.UIBuilderModule")] internal class PropertyHandler : IDisposable { + readonly static Dictionary> s_DefaultObjectReferenceCache = new(); + List m_PropertyDrawers; List m_DecoratorDrawers; public string tooltip; @@ -126,7 +130,7 @@ public void HandleDrawnType(SerializedProperty property, Type drawnType, Type pr if (propertyType != null && propertyType.IsArrayOrList() && !attribute.applyToCollection) return; - var propertyDrawerForType = (PropertyDrawer)System.Activator.CreateInstance(drawerType); + var propertyDrawerForType = CreatePropertyDrawerWithDefaultObjectReferences(drawerType); propertyDrawerForType.m_FieldInfo = field; // Will be null by design if default type drawer! @@ -152,6 +156,47 @@ public void HandleDrawnType(SerializedProperty property, Type drawnType, Type pr } } + static PropertyDrawer CreatePropertyDrawerWithDefaultObjectReferences(Type drawerType) + { + var propertyDrawer = (PropertyDrawer)Activator.CreateInstance(drawerType); + + // We cache the default values for the object references in the drawer as the lookup process can be slow. + if (!s_DefaultObjectReferenceCache.TryGetValue(drawerType, out var defaultObjectReferences)) + { + var monoScript = MonoScript.FromType(drawerType); + if (monoScript != null) + { + using var namePool = ListPool.Get(out var names); + using var targetsPool = ListPool.Get(out var targets); + + MonoImporter.GetDefaultReferencesInternal(monoScript, names, targets); + Debug.Assert(names.Count == targets.Count); + + for (int i = 0; i < names.Count; i++) + { + defaultObjectReferences ??= new List<(FieldInfo, Object)>(); + var field = drawerType.GetField(names[i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + if (field != null) + { + defaultObjectReferences.Add((field, targets[i])); + } + } + } + + s_DefaultObjectReferenceCache[drawerType] = defaultObjectReferences; + } + + if (defaultObjectReferences != null) + { + foreach (var (field, value) in defaultObjectReferences) + { + field.SetValue(propertyDrawer, value); + } + } + + return propertyDrawer; + } + // returns true if children needs to be drawn separately public bool OnGUI(Rect position, SerializedProperty property, GUIContent label, bool includeChildren) { diff --git a/Editor/Mono/Inspector/Core/ScriptAttributeGUI/ScriptAttributeUtility.cs b/Editor/Mono/Inspector/Core/ScriptAttributeGUI/ScriptAttributeUtility.cs index 63aa72ab3a..87598332f1 100644 --- a/Editor/Mono/Inspector/Core/ScriptAttributeGUI/ScriptAttributeUtility.cs +++ b/Editor/Mono/Inspector/Core/ScriptAttributeGUI/ScriptAttributeUtility.cs @@ -674,8 +674,7 @@ internal static PropertyHandler GetHandler(SerializedProperty property) handler.HandleAttribute(property, attributes[i], field, propertyType); } - // Field has no CustomPropertyDrawer attribute with matching drawer so look for default drawer for field type - if (!handler.hasPropertyDrawer && propertyType != null) + if (propertyType != null) handler.HandleDrawnType(property, propertyType, propertyType, field, null); if (handler.empty) diff --git a/Editor/Mono/Inspector/EditorSettingsInspector.cs b/Editor/Mono/Inspector/EditorSettingsInspector.cs index 0407ed384c..34f4f57927 100644 --- a/Editor/Mono/Inspector/EditorSettingsInspector.cs +++ b/Editor/Mono/Inspector/EditorSettingsInspector.cs @@ -75,9 +75,9 @@ class Content public static GUIContent lineEndingForNewScripts = EditorGUIUtility.TrTextContent("Line Endings For New Scripts"); - public static GUIContent streamingSettings = EditorGUIUtility.TrTextContent("Streaming Settings"); - public static GUIContent enablePlayModeTextureStreaming = EditorGUIUtility.TrTextContent("Enable Texture Streaming In Play Mode", "Texture Streaming must be enabled in Quality Settings for mipmap streaming to function in Play Mode. This reduces GPU memory by streaming mips in and out as needed."); - public static GUIContent enableEditModeTextureStreaming = EditorGUIUtility.TrTextContent("Enable Texture Streaming In Edit Mode", "Texture Streaming must be enabled in Quality Settings for mipmap streaming to function in Edit Mode. This reduces GPU memory by streaming mips in and out as needed."); + public static GUIContent streamingSettings = EditorGUIUtility.TrTextContent("Texture Streaming Settings"); + public static GUIContent enablePlayModeTextureStreaming = EditorGUIUtility.TrTextContent("Enable Mipmap Streaming In Play Mode", "Texture Mipmap Streaming must be enabled in Quality Settings for mipmap streaming to function in Play Mode. This reduces GPU memory by streaming mips in and out as needed."); + public static GUIContent enableEditModeTextureStreaming = EditorGUIUtility.TrTextContent("Enable Mipmap Streaming In Edit Mode", "Texture Mipmap Streaming must be enabled in Quality Settings for mipmap streaming to function in Edit Mode. This reduces GPU memory by streaming mips in and out as needed."); public static GUIContent enableEditorAsyncCPUTextureLoading = EditorGUIUtility.TrTextContent("Load texture data on demand", "While in Editor, load CPU side texture data for streaming textures from disk asynchronously on demand (will avoid some stalls and reduce CPU memory usage). Change requires Editor restart."); public static GUIContent shaderCompilation = EditorGUIUtility.TrTextContent("Shader Compilation"); @@ -90,9 +90,21 @@ class Content public static GUIContent prefabModeUIEnvironment = EditorGUIUtility.TrTextContent("UI Environment"); public static readonly GUIContent enterPlayModeSettings = EditorGUIUtility.TrTextContent("Enter Play Mode Settings"); - public static readonly GUIContent enterPlayModeOptionsEnabled = EditorGUIUtility.TrTextContent("Enter Play Mode Options", "Enables options when Entering Play Mode"); - public static readonly GUIContent enterPlayModeOptionsEnableDomainReload = EditorGUIUtility.TrTextContent("Reload Domain", "Enables Domain Reload when Entering Play Mode. Domain reload reinitializes game completely making loading behavior very close to the Player"); - public static readonly GUIContent enterPlayModeOptionsEnableSceneReload = EditorGUIUtility.TrTextContent("Reload Scene", "Enables Scene Reload when Entering Play Mode. Scene reload makes loading behavior and performance characteristics very close to the Player"); + public static readonly GUIContent enterPlayModeOptions = EditorGUIUtility.TrTextContent("When entering Play Mode", "Reload options when entering Play Mode."); + public static readonly GUIContent[] enterPlayModeOptionNames = + { + EditorGUIUtility.TrTextContent("Reload Domain and Scene"), // Default + EditorGUIUtility.TrTextContent("Reload Scene only"), + EditorGUIUtility.TrTextContent("Reload Domain only"), + EditorGUIUtility.TrTextContent("Do not reload Domain or Scene") + }; + public static readonly int[] enterPlayModeOptionValues = + { + (int)EnterPlayModeOptions.None, // Default + (int)EnterPlayModeOptions.DisableDomainReload, + (int)EnterPlayModeOptions.DisableSceneReload, + (int)(EnterPlayModeOptions.DisableDomainReload | EnterPlayModeOptions.DisableSceneReload) + }; public static readonly GUIContent numberingScheme = EditorGUIUtility.TrTextContent("Numbering Scheme"); @@ -987,25 +999,14 @@ private void DoEnterPlayModeSettings() GUILayout.Label(Content.enterPlayModeSettings, EditorStyles.boldLabel); EditorGUI.BeginChangeCheck(); - EditorGUILayout.PropertyField(m_EnterPlayModeOptionsEnabled, Content.enterPlayModeOptionsEnabled); - if (EditorGUI.EndChangeCheck() && m_IsGlobalSettings) - EditorSettings.enterPlayModeOptionsEnabled = m_EnterPlayModeOptionsEnabled.boolValue; - EditorGUI.indentLevel++; - using (new EditorGUI.DisabledScope(!m_EnterPlayModeOptionsEnabled.boolValue)) - { - EnterPlayModeOptions options = (EnterPlayModeOptions)m_EnterPlayModeOptions.intValue; - options = ToggleEnterPlayModeOptions(options, EnterPlayModeOptions.DisableDomainReload, Content.enterPlayModeOptionsEnableDomainReload); - options = ToggleEnterPlayModeOptions(options, EnterPlayModeOptions.DisableSceneReload, Content.enterPlayModeOptionsEnableSceneReload); + EditorGUILayout.IntPopup(m_EnterPlayModeOptions, Content.enterPlayModeOptionNames, Content.enterPlayModeOptionValues, Content.enterPlayModeOptions); - if (m_EnterPlayModeOptions.intValue != (int)options) - { - m_EnterPlayModeOptions.intValue = (int)options; - if (m_IsGlobalSettings) - EditorSettings.enterPlayModeOptions = options; - } + if (EditorGUI.EndChangeCheck() && m_IsGlobalSettings) + { + EditorSettings.enterPlayModeOptionsEnabled = m_EnterPlayModeOptionsEnabled.boolValue; + EditorSettings.enterPlayModeOptions = (EnterPlayModeOptions)m_EnterPlayModeOptions.intValue; } - EditorGUI.indentLevel--; } private void DoEnterInspectorSettings() @@ -1247,23 +1248,6 @@ private void SetLineEndingsForNewScripts(object data) EditorSettings.lineEndingsForNewScripts = (LineEndingsMode)popupIndex; } - private EnterPlayModeOptions ToggleEnterPlayModeOptions(EnterPlayModeOptions options, EnterPlayModeOptions flag, GUIContent content) - { - bool isSet = ((options & flag) == flag); - isSet = EditorGUILayout.Toggle(content, !isSet); - - if (isSet) - { - options &= ~flag; - } - else - { - options |= flag; - } - - return options; - } - [SettingsProvider] internal static SettingsProvider CreateProjectSettingsProvider() { diff --git a/Editor/Mono/Inspector/GraphicsSettingsInspector.cs b/Editor/Mono/Inspector/GraphicsSettingsInspector.cs index 1217348f3b..a97d89e709 100644 --- a/Editor/Mono/Inspector/GraphicsSettingsInspector.cs +++ b/Editor/Mono/Inspector/GraphicsSettingsInspector.cs @@ -36,9 +36,11 @@ internal static class GraphicsSettingsData readonly VisibilityControllerBasedOnRenderPipeline m_VisibilityController = new(); TabbedView m_TabbedView; VisualElement m_CurrentRoot; + ScrollView m_ScrollView; List m_GlobalSettings; bool m_FinishedInitialization; + uint m_LastListsHash; // As we use multiple IMGUI container while porting everything to UITK we will call serializedObject.Update in first separate IMGUI container. // This way we don't need to do it in each following containers. @@ -47,13 +49,20 @@ VisualElement ObjectUpdater() return new IMGUIContainer(() => serializedObject.Update()); } - internal void Reload() + internal void Initialization() { - if (m_FinishedInitialization) + m_LastListsHash = GraphicsSettingsInspectorUtility.ComputeRenderPipelineGlobalSettingsListHash(serializedObject); + } + + internal void Reload(uint hashToCheck) + { + if (m_FinishedInitialization && m_LastListsHash != hashToCheck) { Dispose(); Create(m_CurrentRoot); + + m_LastListsHash = hashToCheck; } } @@ -120,8 +129,8 @@ void Setup(bool globalSettingsExist) GraphicsSettingsInspectorUtility.LocalizeVisualTree(m_CurrentRoot); // Register a callback on the Geometry Change event of the content container.It will be called when the size of all children will be known. - var mainScrollView = m_CurrentRoot.Q("MainScrollView"); - mainScrollView.RegisterCallbackOnce(OnMainScrollViewGeometryChanged); + m_ScrollView = m_CurrentRoot.Q("MainScrollView"); + m_ScrollView.contentContainer.RegisterCallback(OnMainScrollViewGeometryChanged); m_CurrentRoot.Bind(serializedObject); } @@ -177,13 +186,38 @@ void GenerateTabs() } } + int m_GeometryChangedEventCounter; + void OnMainScrollViewGeometryChanged(GeometryChangedEvent evt) { - if (evt.elementTarget is not ScrollView mainScrollView) - throw new InvalidCastException(); + void Unregister() + { + m_ScrollView.contentContainer.UnregisterCallback(OnMainScrollViewGeometryChanged); + m_GeometryChangedEventCounter = 0; + m_FinishedInitialization = true; + } - mainScrollView.scrollOffset = UserSettings.FromConfig().scrollOffset; - m_FinishedInitialization = true; + void UnregisterAfterLastGeometryChange() + { + if (m_GeometryChangedEventCounter > 1) + { + m_GeometryChangedEventCounter--; + return; + } + + Unregister(); + } + + var savedScrollOffset = UserSettings.FromConfig().scrollOffset; + if (m_ScrollView.scrollOffset != savedScrollOffset) + { + m_ScrollView.scrollOffset = savedScrollOffset; + + m_GeometryChangedEventCounter++; + m_ScrollView.contentContainer.schedule.Execute(UnregisterAfterLastGeometryChange).ExecuteLater(500); + } + else + Unregister(); } void BindEnumFieldWithFadeGroup(VisualElement content, string id, Action buttonCallback) @@ -224,12 +258,12 @@ public static void ToConfig(VisualElement root) var userSettings = new UserSettings(); var mainScrollView = root.Q("MainScrollView"); - if (mainScrollView != null) - { - userSettings.scrollOffset = mainScrollView.scrollOffset; - } - var tabbedView = root.Q("PipelineSpecificSettings"); + if (mainScrollView == null) + return; + + userSettings.scrollOffset = mainScrollView.scrollOffset; + if (tabbedView != null && tabbedView.ActiveTab != null) { userSettings.pipelineFullTypeName = tabbedView.ActiveTab.userData.ToString(); @@ -397,6 +431,7 @@ internal GraphicsSettingsProvider(string path, SettingsScope scopes, IEnumerable return; inspector = Editor.CreateEditor(settingsObj) as GraphicsSettingsInspector; + inspector.Initialization(); var content = inspector.Create(root); this.keywords = CreateKeywordsList(content); @@ -404,16 +439,13 @@ internal GraphicsSettingsProvider(string path, SettingsScope scopes, IEnumerable deactivateHandler = (() => { if (inspector != null) + { inspector.Dispose(); + inspector = null; + } }); } - internal void Reload() - { - if(inspector != null) - inspector.Reload(); - } - List CreateKeywordsList(VisualElement content) { var keywordsList = new List(); diff --git a/Editor/Mono/Inspector/GraphicsSettingsInspectors/GraphicsSettingsInspectorUtility.cs b/Editor/Mono/Inspector/GraphicsSettingsInspectors/GraphicsSettingsInspectorUtility.cs index f5537d41ca..ed1ad28c28 100644 --- a/Editor/Mono/Inspector/GraphicsSettingsInspectors/GraphicsSettingsInspectorUtility.cs +++ b/Editor/Mono/Inspector/GraphicsSettingsInspectors/GraphicsSettingsInspectorUtility.cs @@ -300,8 +300,35 @@ internal static void ReloadGraphicsSettingsEditorIfNeeded() return; var settingsWindow = EditorWindow.GetWindow(null, false); - if (settingsWindow.GetCurrentProvider() is GraphicsSettingsProvider provider) - provider.Reload(); + if (settingsWindow.GetCurrentProvider() is not GraphicsSettingsProvider provider) + return; + + if (provider.inspector == null) + return; + + provider.inspector.Reload(ComputeRenderPipelineGlobalSettingsListHash(provider.inspector.serializedObject)); + } + + internal static uint ComputeRenderPipelineGlobalSettingsListHash(SerializedObject graphicsSettingsSerializedObject) + { + if (graphicsSettingsSerializedObject == null) + return 0u; + + bool haveSettings = GraphicsSettingsInspectorUtility.GatherGlobalSettingsFromSerializedObject(graphicsSettingsSerializedObject, out var settingsContainers); + if (!haveSettings) + return 0u; + + uint currentHash = 2166136261u; + foreach (var globalsettings in settingsContainers) + { + TryGetSettingsListFromRenderPipelineGlobalSettings( + globalsettings.serializedObject.targetObject as RenderPipelineGlobalSettings, + out SerializedObject _, + out SerializedProperty _, + out SerializedProperty settingsListInContainer); + currentHash *= 16777619u ^ settingsListInContainer.contentHash; + } + return currentHash; } #endregion diff --git a/Editor/Mono/Inspector/MonoScriptInspector.cs b/Editor/Mono/Inspector/MonoScriptInspector.cs index 28adf2d8f5..bfabd5dd3d 100644 --- a/Editor/Mono/Inspector/MonoScriptInspector.cs +++ b/Editor/Mono/Inspector/MonoScriptInspector.cs @@ -100,7 +100,10 @@ static void ResetDefaultReferences(MenuCommand command) static bool IsTypeCompatible(Type type) { - if (type == null || !(type.IsSubclassOf(typeof(MonoBehaviour)) || type.IsSubclassOf(typeof(ScriptableObject)))) + if (type == null || + !(type.IsSubclassOf(typeof(MonoBehaviour)) || + type.IsSubclassOf(typeof(ScriptableObject)) || + type.IsSubclassOf(typeof(PropertyDrawer)))) return false; return true; } diff --git a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs index ff586f3a8f..b3ed1d5479 100644 --- a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs +++ b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs @@ -23,6 +23,8 @@ using TargetAttributes = UnityEditor.BuildTargetDiscovery.TargetAttributes; using UnityEngine.Rendering; using UnityEngine.Scripting; +using UnityEngine.Bindings; +using UnityEditor.Build.Profile; // ************************************* READ BEFORE EDITING ************************************** // @@ -38,6 +40,7 @@ namespace UnityEditor { [CustomEditor(typeof(PlayerSettings))] + [VisibleToOtherModules("UnityEditor.BuildProfileModule")] internal partial class PlayerSettingsEditor : Editor { class Styles @@ -105,7 +108,7 @@ class SettingsContent public static readonly GUIContent openGLFrameTimingStatsOnGPURecordersOnWarning = EditorGUIUtility.TrTextContent("On OpenGL, Frame Timing Stats may disable Profiler GPU Recorders and the GPU Profiler."); public static readonly GUIContent openGLFrameTimingStatsOnGPURecordersOffInfo = EditorGUIUtility.TrTextContent("On OpenGL, Frame Timing Stats may disable the GPU Profiler."); public static readonly GUIContent openGLFrameTimingStatsOffGPURecordersOnInfo = EditorGUIUtility.TrTextContent("On OpenGL, Profiler GPU Recorders may disable the GPU Profiler."); - public static readonly GUIContent useOSAutoRotation = EditorGUIUtility.TrTextContent("Use Animated Autorotation", "If set OS native animated autorotation method will be used. Otherwise orientation will be changed immediately."); + public static readonly GUIContent useOSAutoRotation = EditorGUIUtility.TrTextContent("Use Animated Autorotation (Deprecated)", "If set OS native animated autorotation method will be used. Otherwise orientation will be changed immediately. This is has no effect on iOS 16 later versions as autorotation is always animated. This option is deprecated and will be removed in a future release."); public static readonly GUIContent defaultScreenWidth = EditorGUIUtility.TrTextContent("Default Screen Width"); public static readonly GUIContent defaultScreenHeight = EditorGUIUtility.TrTextContent("Default Screen Height"); public static readonly GUIContent macRetinaSupport = EditorGUIUtility.TrTextContent("Mac Retina Support"); @@ -234,7 +237,7 @@ class SettingsContent public static readonly GUIContent[] lightmapEncodingNames = { EditorGUIUtility.TrTextContent("Low Quality"), EditorGUIUtility.TrTextContent("Normal Quality"), EditorGUIUtility.TrTextContent("High Quality") }; public static readonly GUIContent hdrCubemapEncodingLabel = EditorGUIUtility.TrTextContent("HDR Cubemap Encoding", "Determines which encoding scheme Unity uses to encode HDR cubemaps."); public static readonly GUIContent[] hdrCubemapEncodingNames = { EditorGUIUtility.TrTextContent("Low Quality"), EditorGUIUtility.TrTextContent("Normal Quality"), EditorGUIUtility.TrTextContent("High Quality") }; - public static readonly GUIContent lightmapStreamingEnabled = EditorGUIUtility.TrTextContent("Lightmap Streaming", "Only load larger lightmap mipmap levels as needed to render the current game cameras. Requires texture streaming to be enabled in quality settings. This value is applied to the light map textures as they are generated."); + public static readonly GUIContent lightmapStreamingEnabled = EditorGUIUtility.TrTextContent("Lightmap Streaming", "Only load larger lightmap mipmap levels as needed to render the current game cameras. Requires texture mipmap streaming to be enabled in quality settings. This value is applied to the light map textures as they are generated."); public static readonly GUIContent lightmapStreamingPriority = EditorGUIUtility.TrTextContent("Streaming Priority", "Lightmap mipmap streaming priority when there's contention for resources. Positive numbers represent higher priority. Valid range is -128 to 127. This value is applied to the light map textures as they are generated."); public static readonly GUIContent legacyClampBlendShapeWeights = EditorGUIUtility.TrTextContent("Clamp BlendShapes (Deprecated)*", "If set, the range of BlendShape weights in SkinnedMeshRenderers will be clamped."); public static readonly GUIContent virtualTexturingSupportEnabled = EditorGUIUtility.TrTextContent("Virtual Texturing (Experimental)*", "Enable Virtual Texturing. This feature is experimental and not ready for production use. Changing this value requires an Editor restart."); @@ -261,9 +264,13 @@ class SettingsContent public static readonly string undoChangedPlatformShaderChunkCountString = L10n.Tr("Changed Shader Chunk Count Platform Setting"); public static readonly string undoChangedDefaultShaderChunkSizeString = L10n.Tr("Changed Shader Chunk Size Default Setting"); public static readonly string undoChangedDefaultShaderChunkCountString = L10n.Tr("Changed Shader Chunk Count Default Setting"); + + public static readonly string globalPlayerSettingsInfo = + L10n.Tr("Editing these global player settings will not affect the current state of the project, because the active build profile is using it's own customized player setitngs. Edit the build profile to change them."); + public static readonly string globalPlayerSettingsInfoButton = L10n.Tr("Edit Build Profile"); } - class RecompileReason + internal class RecompileReason { public static readonly string scriptingDefineSymbolsModified = L10n.Tr("Scripting define symbols setting modified"); public static readonly string suppressCommonWarningsModified = L10n.Tr("Suppress common warnings setting modified"); @@ -512,10 +519,22 @@ public static void SyncColorGamuts() private static Texture2D s_WarningIcon; // Preset check - bool isPreset = false; bool isPresetWindowOpen = false; bool hasPresetWindowClosed = false; + bool IsPreset() => playerSettingsType == PlayerSettingsType.Preset; + + internal enum PlayerSettingsType + { + Global, + Preset, + ActiveBuildProfile, + NonActiveBuildProfile + } + internal PlayerSettingsType playerSettingsType = PlayerSettingsType.Global; + internal bool IsBuildProfile() => playerSettingsType == PlayerSettingsType.ActiveBuildProfile || playerSettingsType == PlayerSettingsType.NonActiveBuildProfile; + bool IsGlobalOrActiveProfile => playerSettingsType == PlayerSettingsType.Global || playerSettingsType == PlayerSettingsType.ActiveBuildProfile; + const string kSelectedPlatform = "PlayerSettings.SelectedPlatform"; public SerializedProperty FindPropertyAssert(string name) @@ -530,7 +549,8 @@ public SerializedProperty FindPropertyAssert(string name) void OnEnable() { s_activeEditors.Add(this); - isPreset = Preset.IsEditorTargetAPreset(target); + if (Preset.IsEditorTargetAPreset(target)) + playerSettingsType = PlayerSettingsType.Preset; validPlatforms = BuildPlatforms.instance.GetValidPlatforms(true).ToArray(); m_StripEngineCode = FindPropertyAssert("stripEngineCode"); @@ -718,10 +738,45 @@ void OnDisable() HandlePendingChangesRequiringRecompilation(); // Ensure script compilation handling is returned to to EditorOnlyPlayerSettings - if (!isPreset) + if (!IsPreset()) PlayerSettings.isHandlingScriptRecompile = true; } + /// + /// Configures the player settings editor for a build profile, ensuring only one platform + /// tab is displayed in the platform grouping. + /// + [VisibleToOtherModules("UnityEditor.BuildProfileModule")] + internal void ConfigurePlayerSettingsForBuildProfile(string buildProfileModuleName, bool isServerBuildProfile, bool isActiveBuildProfile) + { + playerSettingsType = isActiveBuildProfile ? PlayerSettingsType.ActiveBuildProfile : PlayerSettingsType.NonActiveBuildProfile; + + // We don't want to show other platform tabs that it's not the build profile one + bool gotValidPlatform = false; + string platformModuleName = string.Empty; + for (int i = 0; i < validPlatforms.Length; i++) + { + platformModuleName = ModuleManager.GetTargetStringFrom(validPlatforms[i].defaultTarget); + bool isServerPlatform = validPlatforms[i].namedBuildTarget == NamedBuildTarget.Server; + if (platformModuleName == buildProfileModuleName && isServerPlatform == isServerBuildProfile) + { + var copy = (BuildPlatform)validPlatforms[i].Clone(); + copy.tooltip = string.Empty; + validPlatforms[0] = copy; + gotValidPlatform = true; + break; + } + } + + if (!gotValidPlatform) + return; + + Array.Resize(ref validPlatforms, 1); + m_SettingsExtensions = new ISettingEditorExtension[1]; + m_SettingsExtensions[0] = ModuleManager.GetEditorSettingsExtension(platformModuleName); + m_SettingsExtensions[0]?.OnEnable(this); + } + [RequiredByNativeCode] private static void HandlePendingChangesBeforeEnterPlaymode() { @@ -729,6 +784,9 @@ private static void HandlePendingChangesBeforeEnterPlaymode() { editor.HandlePendingChangesRequiringRecompilation(); } + + // Handle build profile pending recompilation. + BuildProfileContext.HandlePendingChangesBeforeEnterPlaymode(); } private void HandlePendingChangesRequiringRecompilation() @@ -802,7 +860,7 @@ internal override string targetTitle private void CheckUpdatePresetSelectorStatus() { - if (isPreset) + if (playerSettingsType != PlayerSettingsType.Global) return; bool isOpen = PresetEditorHelper.presetEditorOpen; @@ -815,7 +873,7 @@ private void CheckUpdatePresetSelectorStatus() private void SetReason(string reason) { - if (isPreset) + if (!IsGlobalOrActiveProfile) { return; } @@ -836,7 +894,7 @@ private string ConvertReasonsToString() private void RecompileScripts() { - if (isPreset || isPresetWindowOpen) + if (!IsGlobalOrActiveProfile || isPresetWindowOpen) { return; } @@ -860,7 +918,7 @@ private void OnPresetSelectorClosed() { hasPresetWindowClosed = false; - if (isPreset) + if (playerSettingsType != PlayerSettingsType.Global) return; if (HasReasonToCompile()) @@ -873,6 +931,8 @@ private void OnPresetSelectorClosed() public override void OnInspectorGUI() { + DisplayBuildProfileHelpBoxIfNeeded(); + var serializedObjectUpdated = serializedObject.UpdateIfRequiredOrScript(); EditorGUILayout.BeginVertical(); { @@ -909,12 +969,11 @@ public override void OnInspectorGUI() BuildPlatform platform = validPlatforms[selectedPlatformValue]; - if (!isPreset) - { + if (playerSettingsType == PlayerSettingsType.Global) CheckUpdatePresetSelectorStatus(); - } - GUILayout.Label(string.Format(L10n.Tr("Settings for {0}"), validPlatforms[selectedPlatformValue].title.text)); + if (!IsBuildProfile()) + GUILayout.Label(string.Format(L10n.Tr("Settings for {0}"), validPlatforms[selectedPlatformValue].title.text)); // Increase the offset to accomodate large labels, though keep a minimum of 150. EditorGUIUtility.labelWidth = Mathf.Max(150, EditorGUIUtility.labelWidth + 4); @@ -932,7 +991,7 @@ public override void OnInspectorGUI() m_IconsEditor.IconSectionGUI(platform.namedBuildTarget, m_SettingsExtensions[selectedPlatformValue], selectedPlatformValue, sectionIndex++); - ResolutionSectionGUI(platform.namedBuildTarget, m_SettingsExtensions[selectedPlatformValue], sectionIndex++); + ResolutionSectionGUI(platform, m_SettingsExtensions[selectedPlatformValue], sectionIndex++); m_SplashScreenEditor.SplashSectionGUI(platform, m_SettingsExtensions[selectedPlatformValue], sectionIndex++); DebugAndCrashReportingGUI(platform, m_SettingsExtensions[selectedPlatformValue], sectionIndex++); OtherSectionGUI(platform, m_SettingsExtensions[selectedPlatformValue], sectionIndex++); @@ -959,6 +1018,26 @@ public override void OnInspectorGUI() } } + void DisplayBuildProfileHelpBoxIfNeeded() + { + if (playerSettingsType == PlayerSettingsType.Global && BuildProfileContext.instance.activeProfile?.playerSettings != null) + { + GUILayout.BeginHorizontal(EditorStyles.helpBox); + GUILayout.BeginVertical(); + GUILayout.Space(5); + GUILayout.Label(EditorGUIUtility.GetHelpIcon(MessageType.Warning), GUILayout.ExpandWidth(false)); + GUILayout.EndVertical(); + GUILayout.Label(SettingsContent.globalPlayerSettingsInfo, EditorStyles.wordWrappedMiniLabel); + GUILayout.BeginVertical(); + GUILayout.Space(5); + if (GUILayout.Button(SettingsContent.globalPlayerSettingsInfoButton)) + BuildPipeline.ShowBuildProfileWindow(); + GUILayout.Space(5); + GUILayout.EndVertical(); + GUILayout.EndHorizontal(); + } + } + private void CommonSettings() { EditorGUILayout.PropertyField(m_CompanyName); @@ -1026,8 +1105,9 @@ private static bool TargetSupportsOptionalBuiltinSplashScreen(BuildTargetGroup t return targetGroup == BuildTargetGroup.Standalone; } - public void ResolutionSectionGUI(NamedBuildTarget namedBuildTarget, ISettingEditorExtension settingsExtension, int sectionIndex = 0) + public void ResolutionSectionGUI(BuildPlatform platform, ISettingEditorExtension settingsExtension, int sectionIndex = 0) { + NamedBuildTarget namedBuildTarget = platform.namedBuildTarget; if (BeginSettingsBox(sectionIndex, SettingsContent.resolutionPresentationTitle)) { // PLEASE DO NOT COPY SETTINGS TO APPEAR MULTIPLE PLACES IN THE CODE! See top of file for more info. @@ -1087,7 +1167,9 @@ public void ResolutionSectionGUI(NamedBuildTarget namedBuildTarget, ISettingEdit EditorGUILayout.EndFadeGroup(); } - if (namedBuildTarget == NamedBuildTarget.Standalone) + if (namedBuildTarget == NamedBuildTarget.Standalone && + BuildTargetDiscovery.TryGetProperties(platform.defaultTarget, out IGraphicsPlatformProperties properties) && + (properties?.RetinaSupport ?? false)) EditorGUILayout.PropertyField(m_MacRetinaSupport, SettingsContent.macRetinaSupport); if (settingsExtension != null && settingsExtension.SupportsOrientation()) @@ -1407,7 +1489,7 @@ private static bool WillEditorUseFirstGraphicsAPI(BuildTarget targetPlatform) private bool CheckApplyGraphicsJobsModeChange() { bool doRestart = false; - + // If we have dirty scenes we need to save or discard changes before we restart editor. // Otherwise user will get a dialog later on where they can click cancel and put editor in a bad device state. var dirtyScenes = new List(); @@ -1496,7 +1578,7 @@ void ExclusiveGraphicsAPIsGUI(BuildTarget targetPlatform, string displayTitle) void GraphicsAPIsGUIOnePlatform(BuildTargetGroup targetGroup, BuildTarget targetPlatform, string platformTitle) { - if (isPreset) + if (IsPreset()) return; GraphicsDeviceType[] availableDevices = PlayerSettings.GetSupportedGraphicsAPIs(targetPlatform); @@ -1678,13 +1760,20 @@ private void DrawColorGamutElement(BuildTargetGroup targetGroup, Rect rect, int GUI.Label(rect, GetColorGamutDisplayString(targetGroup, (ColorGamut)colorGamut), EditorStyles.label); } - void ColorGamutGUI(BuildTargetGroup targetGroup) + void ColorGamutGUI(BuildPlatform platform) { - if (isPreset) + BuildTargetGroup targetGroup = platform.namedBuildTarget.ToBuildTargetGroup(); + + if (IsPreset()) return; if (!s_SupportedColorGamuts.ContainsKey(targetGroup)) return; + // Color gamut is not supported for other standalones besides Mac + if (!(BuildTargetDiscovery.TryGetProperties(platform.defaultTarget, out IGraphicsPlatformProperties properties) && + (properties?.SupportsColorGamut ?? false))) + return; + if (s_ColorGamutList == null) { ColorGamut[] colorGamuts = PlayerSettings.GetColorGamuts(); @@ -1967,7 +2056,7 @@ private void OtherSectionRenderingGUI(BuildPlatform platform, ISettingEditorExte } // Output color spaces - ColorGamutGUI(platform.namedBuildTarget.ToBuildTargetGroup()); + ColorGamutGUI(platform); // What we call "Metal Validation" is a random bunch of extra checks we do in editor in metal code if (Application.platform == RuntimePlatform.OSXEditor && BuildTargetDiscovery.BuildTargetSupportsRenderer(platform, GraphicsDeviceType.Metal)) @@ -1984,7 +2073,7 @@ private void OtherSectionRenderingGUI(BuildPlatform platform, ISettingEditorExte BuildEnumPopup(m_FramebufferDepthMemorylessMode, SettingsContent.framebufferDepthMemorylessMode, memorylessModeValues, SettingsContent.memorylessModeNames); } - if (!isPreset) + if (!IsPreset()) { // Multithreaded rendering if (settingsExtension != null && settingsExtension.SupportsMultithreadedRendering()) @@ -2184,7 +2273,7 @@ private void OtherSectionRenderingGUI(BuildPlatform platform, ISettingEditorExte } } - if (!isPreset) + if (!IsPreset()) { EditorGUI.BeginChangeCheck(); GUIContent graphicsJobsGUI = SettingsContent.graphicsJobsNonExperimental; @@ -2266,7 +2355,7 @@ private void OtherSectionRenderingGUI(BuildPlatform platform, ISettingEditorExte } } - if ((settingsExtension != null && settingsExtension.SupportsCustomNormalMapEncoding()) && !isPreset) + if ((settingsExtension != null && settingsExtension.SupportsCustomNormalMapEncoding()) && !IsPreset()) { using (new EditorGUI.DisabledScope(EditorApplication.isPlaying || Lightmapping.isRunning)) { @@ -2284,7 +2373,7 @@ private void OtherSectionRenderingGUI(BuildPlatform platform, ISettingEditorExte } // Show Lightmap Encoding and HDR Cubemap Encoding quality options - if (hdrEncodingSupportedByPlatform && !isPreset) + if (hdrEncodingSupportedByPlatform && !IsPreset()) { using (new EditorGUI.DisabledScope(EditorApplication.isPlaying || Lightmapping.isRunning)) { @@ -2324,7 +2413,7 @@ private void OtherSectionRenderingGUI(BuildPlatform platform, ISettingEditorExte } } - if (!isPreset) + if (!IsPreset()) { // Light map settings using (new EditorGUI.DisabledScope(EditorApplication.isPlaying || Lightmapping.isRunning)) @@ -2484,7 +2573,7 @@ private void OtherSectionRenderingGUI(BuildPlatform platform, ISettingEditorExte } } } - if (!isPreset) + if (!IsPreset()) EditorGUILayout.Space(); Stereo360CaptureGUI(platform.namedBuildTarget.ToBuildTargetGroup()); @@ -2578,7 +2667,7 @@ private void OtherSectionIdentificationGUI(BuildPlatform platform, ISettingEdito EditorGUILayout.Space(); } - else if (platform.namedBuildTarget.ToBuildTargetGroup() == BuildTargetGroup.Standalone) + else if (platform.namedBuildTarget.ToBuildTargetGroup() == BuildTargetGroup.Standalone && CanShowPlatformSettingsForHostPlatform(BuildTarget.StandaloneOSX, platform)) { // TODO this should be move to an extension if we have one for MacOS or Standalone target at some point. GUILayout.Label(SettingsContent.macAppStoreTitle, EditorStyles.boldLabel); @@ -2612,7 +2701,7 @@ private void OtherSectionVulkanSettingsGUI(BuildPlatform platform, ISettingEdito return; GUILayout.Label(SettingsContent.vulkanSettingsTitle, EditorStyles.boldLabel); - if (!isPreset) + if (!IsPreset()) { PlayerSettings.vulkanEnableSetSRGBWrite = EditorGUILayout.Toggle(SettingsContent.vulkanEnableSetSRGBWrite, PlayerSettings.vulkanEnableSetSRGBWrite); EditorGUILayout.PropertyField(m_VulkanNumSwapchainBuffers, SettingsContent.vulkanNumSwapchainBuffers); @@ -3081,7 +3170,7 @@ private void OtherSectionConfigurationGUI(BuildPlatform platform, ISettingEditor EditorGUILayout.Space(); - if (platform.namedBuildTarget == NamedBuildTarget.Standalone) + if (platform.namedBuildTarget == NamedBuildTarget.Standalone && CanShowPlatformSettingsForHostPlatform(BuildTarget.StandaloneOSX, platform)) { GUILayout.Label(SettingsContent.macConfigurationTitle, EditorStyles.boldLabel); @@ -3375,12 +3464,12 @@ private void OtherSectionOptimizationGUI(BuildPlatform platform) EditorGUILayout.PropertyField(m_BakeCollisionMeshes, SettingsContent.bakeCollisionMeshes); - if (isPreset) + if (IsPreset()) EditorGUI.indentLevel++; EditorGUILayout.PropertyField(m_PreloadedAssets, SettingsContent.preloadedAssets, true); - if (isPreset) + if (IsPreset()) EditorGUI.indentLevel--; bool platformUsesAOT = @@ -3544,7 +3633,7 @@ private void OtherSectionLoggingGUI() { logProperty.intValue = (int)stackTraceLogType; - if (!isPreset) + if (IsGlobalOrActiveProfile) PlayerSettings.SetGlobalStackTraceLogType(logType, stackTraceLogType); } } @@ -3961,5 +4050,13 @@ private void FindPlayerSettingsAttributeSections() m_boxes.Sort((a, b) => a.order.CompareTo(b.order)); } + + bool CanShowPlatformSettingsForHostPlatform(BuildTarget settingsBuildTarget, BuildPlatform currentPlatform) + { + if (IsBuildProfile() && currentPlatform.defaultTarget != settingsBuildTarget) + return false; + + return BuildTargetDiscovery.BuildPlatformIsAvailableOnHostPlatform(settingsBuildTarget, SystemInfo.operatingSystemFamily); + } } } diff --git a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsIconsEditor.cs b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsIconsEditor.cs index 87c79bd3a7..ca21a476cf 100644 --- a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsIconsEditor.cs +++ b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsIconsEditor.cs @@ -436,7 +436,7 @@ public void IconSectionGUI(NamedBuildTarget namedBuildTarget, ISettingEditorExte // consider the icon overridden for this platform EditorGUI.BeginChangeCheck(); overrideIcons = (icons.Length == widths.Length); - overrideIcons = GUILayout.Toggle(overrideIcons, string.Format(L10n.Tr("Override for {0}"), platform.title.text)); + overrideIcons = GUILayout.Toggle(overrideIcons, IsInBuildProfileEditor() ? L10n.Tr("Override") : string.Format(L10n.Tr("Override for {0}"), platform.title.text)); EditorGUI.BeginDisabled(!overrideIcons); var changed = EditorGUI.EndChangeCheck(); if (changed || (!overrideIcons && icons.Length > 0)) @@ -575,5 +575,13 @@ internal void ShowPlatformIconsByKind(PlatformIconFieldGroup iconFieldGroup, boo } } } + + /// + /// Check if this class belongs to the build profile editor + /// + bool IsInBuildProfileEditor() + { + return m_Owner.IsBuildProfile(); + } } } diff --git a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsSplashScreenEditor.bindings.cs b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsSplashScreenEditor.bindings.cs index fccb7b717d..050a9c0414 100644 --- a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsSplashScreenEditor.bindings.cs +++ b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsSplashScreenEditor.bindings.cs @@ -12,12 +12,6 @@ namespace UnityEditor [NativeHeader("Runtime/Graphics/DrawSplashScreenAndWatermarks.h")] internal partial class PlayerSettingsSplashScreenEditor { - internal static extern bool licenseAllowsDisabling - { - [FreeFunction("GetPlayerSettings().GetSplashScreenSettings().CanDisableSplashScreen")] - get; - } - [FreeFunction("GetSplashScreenBackgroundColor")] internal static extern Color GetSplashScreenActualBackgroundColor(); diff --git a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsSplashScreenEditor.cs b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsSplashScreenEditor.cs index 6025d723be..5ae057fdc2 100644 --- a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsSplashScreenEditor.cs +++ b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsSplashScreenEditor.cs @@ -46,8 +46,7 @@ internal partial class PlayerSettingsSplashScreenEditor static readonly float k_LogoListUnityLogoMaxWidth = 220; static readonly float k_LogoListPropertyMinWidth = 230; static readonly float k_LogoListPropertyLabelWidth = 100; - static readonly float k_MinPersonalEditionOverlayOpacity = 0.5f; - static readonly float k_MinProEditionOverlayOpacity = 0.0f; + static readonly float k_MinOverlayOpacity = 0.0f; static readonly Color32 k_DarkOnLightBgColor = new Color32(204, 204, 204, 255);// #CCCCCC static readonly Color32 k_LightOnDarkBgColor = new Color32(35, 31, 32, 255); @@ -345,12 +344,9 @@ private void BuiltinCustomSplashScreenGUI(BuildTargetGroup targetGroup, ISetting { EditorGUILayout.LabelField(k_Texts.splashTitle, EditorStyles.boldLabel); - using (new EditorGUI.DisabledScope(!licenseAllowsDisabling)) - { - EditorGUILayout.PropertyField(m_ShowUnitySplashScreen, k_Texts.showSplash); - if (!m_ShowUnitySplashScreen.boolValue) - return; - } + EditorGUILayout.PropertyField(m_ShowUnitySplashScreen, k_Texts.showSplash); + if (!m_ShowUnitySplashScreen.boolValue) + return; GUIContent buttonLabel = SplashScreen.isFinished ? k_Texts.previewSplash : k_Texts.cancelPreviewSplash; Rect previewButtonRect = GUILayoutUtility.GetRect(buttonLabel, "button"); @@ -404,21 +400,19 @@ private void BuiltinCustomSplashScreenGUI(BuildTargetGroup targetGroup, ISetting // Logos EditorGUILayout.LabelField(k_Texts.logosTitle, EditorStyles.boldLabel); - using (new EditorGUI.DisabledScope(!Application.HasProLicense())) - { - EditorGUI.BeginChangeCheck(); - EditorGUILayout.PropertyField(m_ShowUnitySplashLogo, k_Texts.showLogo); - if (EditorGUI.EndChangeCheck()) - { - if (!m_ShowUnitySplashLogo.boolValue) - RemoveUnityLogoFromLogosList(); - else if (m_SplashScreenDrawMode.intValue == (int)PlayerSettings.SplashScreen.DrawMode.AllSequential) - AddUnityLogoToLogosList(); - } - m_ShowLogoControlsAnimator.target = m_ShowUnitySplashLogo.boolValue; + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_ShowUnitySplashLogo, k_Texts.showLogo); + if (EditorGUI.EndChangeCheck()) + { + if (!m_ShowUnitySplashLogo.boolValue) + RemoveUnityLogoFromLogosList(); + else if (m_SplashScreenDrawMode.intValue == (int)PlayerSettings.SplashScreen.DrawMode.AllSequential) + AddUnityLogoToLogosList(); } + m_ShowLogoControlsAnimator.target = m_ShowUnitySplashLogo.boolValue; + if (EditorGUILayout.BeginFadeGroup(m_ShowLogoControlsAnimator.faded)) { EditorGUI.BeginChangeCheck(); @@ -445,7 +439,7 @@ private void BuiltinCustomSplashScreenGUI(BuildTargetGroup targetGroup, ISetting // Background EditorGUILayout.LabelField(k_Texts.backgroundTitle, EditorStyles.boldLabel); - EditorGUILayout.Slider(m_SplashScreenOverlayOpacity, Application.HasProLicense() ? k_MinProEditionOverlayOpacity : k_MinPersonalEditionOverlayOpacity, 1.0f, k_Texts.overlayOpacity); + EditorGUILayout.Slider(m_SplashScreenOverlayOpacity, k_MinOverlayOpacity, 1.0f, k_Texts.overlayOpacity); m_ShowBackgroundColorAnimator.target = m_SplashScreenBackgroundLandscape.objectReferenceValue == null || (settingsExtension?.SupportsStaticSplashScreenBackgroundColor() ?? false); if (EditorGUILayout.BeginFadeGroup(m_ShowBackgroundColorAnimator.faded)) diff --git a/Editor/Mono/Inspector/QualitySettingsEditor.cs b/Editor/Mono/Inspector/QualitySettingsEditor.cs index 6d19adc414..e18ad46866 100644 --- a/Editor/Mono/Inspector/QualitySettingsEditor.cs +++ b/Editor/Mono/Inspector/QualitySettingsEditor.cs @@ -55,12 +55,12 @@ private class Content public static readonly string kTextureMipmapLimitGroupsDialogMessageOnUpdateAssetsError = L10n.Tr("An error occured while updating texture assets: {0}"); public static readonly string kTextureMipmapLimitGroupsDialogMessageOnIdentifyFail = L10n.Tr("No textures are linked to the mipmap limit group '{0}'."); - public static readonly GUIContent kStreamingMipmapsActive = EditorGUIUtility.TrTextContent("Texture Streaming", "When enabled, Unity only streams texture mipmap levels relevant to the current Camera's position in a Scene. This reduces the total amount of memory Unity needs for textures. Individual textures must also have 'Stream Mipmap Levels' enabled in their Import Settings."); + public static readonly GUIContent kStreamingMipmapsActive = EditorGUIUtility.TrTextContent("Mipmap Streaming", "When enabled, Unity only streams texture mipmap levels relevant to the current Camera's position in a Scene. This reduces the total amount of memory Unity needs for textures. Individual textures must also have 'Stream Mipmap Levels' enabled in their Import Settings."); public static readonly GUIContent kStreamingMipmapsMemoryBudget = EditorGUIUtility.TrTextContent("Memory Budget", "The amount of memory (in megabytes) to allocate for all loaded textures."); public static readonly GUIContent kStreamingMipmapsRenderersPerFrame = EditorGUIUtility.TrTextContent("Renderers Per Frame", "The number of renderers to process each frame. A lower number decreases the CPU load but delays mipmap loading."); - public static readonly GUIContent kStreamingMipmapsAddAllCameras = EditorGUIUtility.TrTextContent("Add All Cameras", "When enabled, Unity uses texture streaming for every Camera in the Scene. Otherwise, Unity only uses texture streaming for Cameras that have an attached Streaming Controller component."); + public static readonly GUIContent kStreamingMipmapsAddAllCameras = EditorGUIUtility.TrTextContent("Add All Cameras", "When enabled, Unity uses mipmap streaming for every Camera in the Scene. Otherwise, Unity only uses mipmap streaming for Cameras that have an attached Streaming Controller component."); public static readonly GUIContent kStreamingMipmapsMaxLevelReduction = EditorGUIUtility.TrTextContent("Max Level Reduction", "The maximum number of mipmap levels a texture can drop."); - public static readonly GUIContent kStreamingMipmapsMaxFileIORequests = EditorGUIUtility.TrTextContent("Max IO Requests", "The maximum number of texture file requests from the Texture Streaming system that can be active at the same time."); + public static readonly GUIContent kStreamingMipmapsMaxFileIORequests = EditorGUIUtility.TrTextContent("Max IO Requests", "The maximum number of texture file requests from the Mipmap Streaming system that can be active at the same time."); public static readonly GUIContent kIconTrash = EditorGUIUtility.TrIconContent("TreeEditor.Trash", "Delete Level"); public static readonly GUIContent kSoftParticlesHint = EditorGUIUtility.TrTextContent("Soft Particles require either the Deferred Shading rendering path or Cameras that render depth textures."); diff --git a/Editor/Mono/Inspector/StreamingControllerInspector.cs b/Editor/Mono/Inspector/StreamingControllerInspector.cs index 7f71b3f658..7b83093722 100644 --- a/Editor/Mono/Inspector/StreamingControllerInspector.cs +++ b/Editor/Mono/Inspector/StreamingControllerInspector.cs @@ -15,7 +15,7 @@ internal class StreamingControllerEditor : Editor internal static class Styles { - public static GUIContent streamingMipmapBias = EditorGUIUtility.TrTextContent("Mipmap Bias", "When texture streaming is active, Unity loads mipmap levels for textures based on their distance from all active cameras. This bias is added to all textures visible from this camera and allows you to force smaller or larger mipmap levels to be loaded for textures visible from this camera."); + public static GUIContent streamingMipmapBias = EditorGUIUtility.TrTextContent("Mipmap Bias", "When mipmap streaming is active, Unity loads mipmap levels for textures based on their distance from all active cameras. This bias is added to all textures visible from this camera and allows you to force smaller or larger mipmap levels to be loaded for textures visible from this camera."); } public void OnEnable() diff --git a/Editor/Mono/Inspector/UnityEventDrawer.cs b/Editor/Mono/Inspector/UnityEventDrawer.cs index ea2efbb887..f20be3325b 100644 --- a/Editor/Mono/Inspector/UnityEventDrawer.cs +++ b/Editor/Mono/Inspector/UnityEventDrawer.cs @@ -55,12 +55,6 @@ protected class State internal const string kBoolArgument = "m_BoolArgument"; internal const string kObjectArgumentAssemblyTypeName = "m_ObjectArgumentAssemblyTypeName"; - //property path splits and separators - private const string kDotString = "."; - private const string kArrayDataString = "Array.data["; - private static readonly char[] kDotSeparator = { '.' }; - private static readonly char[] kClosingSquareBraceSeparator = { ']' }; - // uss names internal const string kUssClassName = "unity-event"; internal const string kLeftColumnClassName = kUssClassName + "__left-column"; @@ -160,6 +154,7 @@ private ListView CreateListView(SerializedProperty property) { showAddRemoveFooter = true, reorderMode = ListViewReorderMode.Animated, + reorderable = true, showBorder = true, showFoldoutHeader = false, showBoundCollectionSize = false, diff --git a/Editor/Mono/Inspector/VisualElements/ObjectFieldWithPrompt.cs b/Editor/Mono/Inspector/VisualElements/ObjectFieldWithPrompt.cs index fd698a7e2b..142ddbd05e 100644 --- a/Editor/Mono/Inspector/VisualElements/ObjectFieldWithPrompt.cs +++ b/Editor/Mono/Inspector/VisualElements/ObjectFieldWithPrompt.cs @@ -3,6 +3,8 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; +using System.Text; +using Unity.Properties; using UnityEngine; using UnityEngine.UIElements; using Object = UnityEngine.Object; @@ -11,6 +13,11 @@ namespace UnityEditor.UIElements { internal class ObjectFieldWithPrompt : BaseField { + static readonly BindingId titleProperty = nameof(title); + static readonly BindingId messageProperty = nameof(message); + static readonly BindingId objectTypeProperty = nameof(objectType); + static readonly BindingId allowSceneObjectsProperty = nameof(allowSceneObjects); + [UnityEngine.Internal.ExcludeFromDocs, Serializable] public new class UxmlSerializedData : BaseField.UxmlSerializedData { @@ -45,22 +52,36 @@ public override void Deserialize(object obj) string m_Title; + [CreateProperty] public string title { get => m_Title; - set => m_Title = value; + set + { + if (string.Equals(m_Title, value, StringComparison.Ordinal)) + return; + m_Title = value; + NotifyPropertyChanged(titleProperty); + } } string m_Message; + [CreateProperty] public string message { get => m_Message; - set => m_Message = value; + set + { + if (m_Message == value) return; + m_Message = value; + NotifyPropertyChanged(messageProperty); + } } Type m_objectType; + [CreateProperty] public Type objectType { get { return m_objectType; } @@ -69,11 +90,13 @@ public Type objectType if (m_objectType == value) return; m_objectType = value; m_ObjectField.objectType = value; + NotifyPropertyChanged(objectTypeProperty); } } bool m_AllowSceneObjects; + [CreateProperty] public bool allowSceneObjects { get => m_AllowSceneObjects; @@ -82,6 +105,7 @@ public bool allowSceneObjects if (m_AllowSceneObjects == value) return; m_AllowSceneObjects = value; m_ObjectField.allowSceneObjects = value; + NotifyPropertyChanged(allowSceneObjectsProperty); } } @@ -106,23 +130,54 @@ public ObjectFieldWithPrompt(string label) : base(label, null) marginRight = 0 } }; + m_ObjectField.SelectorClosed += (obj, canceled) => + { + if (canceled) + return; // User pressed the Escape Key + + // Delay the change call to avoid calling DestroyImmediate from the ObjectSelector. + EditorApplication.delayCall += () => ChangeObject(obj); + }; m_ObjectField.RegisterValueChangedCallback(evt => { - if (EditorUtility.DisplayDialog(title, message, "Confirm", "Cancel")) - value = evt.newValue; - else - m_ObjectField.SetValueWithoutNotify(value); + if (!ObjectSelector.isVisible) + { + // If the Object Selector is NOT visible that means that the user performed a Drag&Drop into the field with a valid asset. + if (ChangeObject(evt.newValue)) + return; + } - if (EditorWindow.HasOpenInstances()) - ObjectSelector.get.Cancel(); + // The UI with the actual backend value might be out of sync as the ObjectSelector or the Drag&Drop might + // have changed the display value. Keep them in sync. + m_ObjectField.SetValueWithoutNotify(value); }); Add(m_ObjectField); } + private static StringBuilder s_MessageBuilder = new StringBuilder(); + + private bool ChangeObject(Object newValue) + { + if (value != newValue) + { + s_MessageBuilder.Clear(); + s_MessageBuilder.AppendLine(message); + s_MessageBuilder.AppendLine(); + s_MessageBuilder.AppendLine($"Current Value: {(value ? value.name : "None")}."); + s_MessageBuilder.AppendLine($"New Value: {(newValue ? newValue.name : "None")}."); + if (EditorUtility.DisplayDialog(title, s_MessageBuilder.ToString(), "Confirm", "Cancel")) + { + value = newValue; + return true; + } + } + + return false; + } + public override void SetValueWithoutNotify(Object newValue) { base.SetValueWithoutNotify(newValue); - m_ObjectField.SetValueWithoutNotify(newValue); } } diff --git a/Editor/Mono/Inspector/VisualElements/ProjectSettings/TabButton.cs b/Editor/Mono/Inspector/VisualElements/ProjectSettings/TabButton.cs index aa3a1e535a..818111124a 100644 --- a/Editor/Mono/Inspector/VisualElements/ProjectSettings/TabButton.cs +++ b/Editor/Mono/Inspector/VisualElements/ProjectSettings/TabButton.cs @@ -114,9 +114,12 @@ public void Select() void RecalculateBottomBarPosition() { + //we need to calculate the width of the bottom bar based on the tab width and remove border width from left and right m_BottomBar.style.width = layout.width - resolvedStyle.borderRightWidth - resolvedStyle.borderLeftWidth; - m_BottomBar.style.top = parent.layout.height; - m_BottomBar.style.left = m_BottomBar.parent.resolvedStyle.paddingLeft + resolvedStyle.borderLeftWidth + layout.x; + //we extract additional padding from the parent to get the correct position + tab height + m_BottomBar.style.top = (parent.worldBound.y - parent.parent.worldBound.y) + parent.layout.height; + //we extract additional padding from the parent to get the correct position + tab position x + border width + m_BottomBar.style.left = (parent.worldBound.x - parent.parent.worldBound.x) + layout.x + resolvedStyle.borderLeftWidth; } public void Deselect() diff --git a/Editor/Mono/InternalEditorUtility.cs b/Editor/Mono/InternalEditorUtility.cs index fac2158ae5..3f3bfc1672 100644 --- a/Editor/Mono/InternalEditorUtility.cs +++ b/Editor/Mono/InternalEditorUtility.cs @@ -308,8 +308,7 @@ internal static List GetNewSelection(ref AssetReference clickedEntry, List< var newSelection = new List(selectedInstanceIDs); if (newSelection.Contains(clickedEntry.instanceID)) { - // In case the user is performing CTRL+click on an already selected item, delay the deselection so that Drag may be initiated. - if (!(Event.current.control && Event.current.type == EventType.MouseDown)) + if (!keepMultiSelection) newSelection.Remove(clickedEntry.instanceID); } else @@ -667,6 +666,8 @@ public static void SetShowGizmos(bool value) } private static Material blitSceneViewCaptureMat; + + [Obsolete("Use CaptureEditorWindow instead", false)] public static bool CaptureSceneView(SceneView sv, RenderTexture rt) { if (!sv.hasFocus) @@ -687,6 +688,27 @@ public static bool CaptureSceneView(SceneView sv, RenderTexture rt) return true; } + public static bool CaptureEditorWindow(EditorWindow window, RenderTexture rt) + { + if (!window.hasFocus) + { + Debug.LogError("CaptureEditorWindow: window must have focus"); + return false; + } + + blitSceneViewCaptureMat = blitSceneViewCaptureMat ?? (Material)EditorGUIUtility.LoadRequired("SceneView/BlitSceneViewCapture.mat"); + + // Grab SceneView framebuffer into a temporary RT. + RenderTexture tmp = RenderTexture.GetTemporary(rt.descriptor); + Rect rect = new Rect(0, 0, window.position.width, window.position.height); + window.m_Parent.GrabPixels(tmp, rect); + + // Blit it into the target RT, it will be flipped by the shader if necessary. + Graphics.Blit(tmp, rt, blitSceneViewCaptureMat); + RenderTexture.ReleaseTemporary(tmp); + + return true; + } static readonly Regex k_UnityAssemblyRegex = new("^(Unity|UnityEditor|UnityEngine).", RegexOptions.Compiled); internal static bool IsUnityAssembly(Type type) diff --git a/Editor/Mono/Modules/DefaultBuildProfileExtension.cs b/Editor/Mono/Modules/DefaultBuildProfileExtension.cs index 9b74e3232d..73bdcaf788 100644 --- a/Editor/Mono/Modules/DefaultBuildProfileExtension.cs +++ b/Editor/Mono/Modules/DefaultBuildProfileExtension.cs @@ -99,8 +99,8 @@ public VisualElement CreateSettingsGUI( if (platformWarningsGUI != null) settingsGUI.Add(platformWarningsGUI); settingsGUI.Add(platformSettingsGUI); - if (m_IsClassicProfile && BuildPlayerWindow.WillDrawMultiplayerBuildOptions()) - settingsGUI.Add(CreateMultiplayerSettingsGUI()); + if (BuildPlayerWindow.WillDrawMultiplayerBuildOptions()) + settingsGUI.Add(CreateMultiplayerSettingsGUI(serializedObject.targetObject as BuildProfile)); settingsGUI.Add(commonSettingsGUI); return settingsGUI; } @@ -170,14 +170,14 @@ public VisualElement CreateCommonSettingsGUI(SerializedObject serializedObject, }); } - VisualElement CreateMultiplayerSettingsGUI() + VisualElement CreateMultiplayerSettingsGUI(BuildProfile profile) { return new IMGUIContainer( () => { var oldLabelWidth = EditorGUIUtility.labelWidth; EditorGUIUtility.labelWidth = labelWidth; - BuildPlayerWindow.DrawMultiplayerBuildOption(m_NamedBuildTarget); + BuildPlayerWindow.DrawMultiplayerBuildOption(profile); EditorGUIUtility.labelWidth = oldLabelWidth; }); } diff --git a/Editor/Mono/MonoScript.bindings.cs b/Editor/Mono/MonoScript.bindings.cs index 31689c2b88..0088dc1395 100644 --- a/Editor/Mono/MonoScript.bindings.cs +++ b/Editor/Mono/MonoScript.bindings.cs @@ -34,10 +34,22 @@ public static MonoScript FromScriptableObject(ScriptableObject scriptableObject) return FromScriptedObject(scriptableObject); } + // Returns the MonoScript object containing the specified Type. + // Note we only store one type per MonoScript. Therefore, if the file contains multiple types, we will return null for the other types. + internal static MonoScript FromType(Type type) + { + if (type == null) + return null; + return FromTypeInternal(type.Name, type.Namespace, type.Assembly.GetName().Name); + } + // Returns the MonoScript object used by the given scripted object [FreeFunction] internal static extern MonoScript FromScriptedObject(UnityEngine.Object obj); + [FreeFunction] + internal static extern MonoScript FromTypeInternal(string className, string nameSpace, string assemblyName); + internal extern bool GetScriptTypeWasJustCreatedFromComponentMenu(); internal extern void SetScriptTypeWasJustCreatedFromComponentMenu(); diff --git a/Editor/Mono/Overlays/OverlayContainerDropZone.cs b/Editor/Mono/Overlays/OverlayContainerDropZone.cs index 859604604d..819fbe031d 100644 --- a/Editor/Mono/Overlays/OverlayContainerDropZone.cs +++ b/Editor/Mono/Overlays/OverlayContainerDropZone.cs @@ -31,10 +31,16 @@ public OverlayContainerDropZone(OverlayContainer container, Placement placement, m_HideIfHovered = hideIfHovered; } + public override void Activate(Overlay draggedOverlay) + { + base.Activate(draggedOverlay); + + SetHidden(false); + } + protected override bool ShouldEnable(Overlay draggedOverlay) { - return (originContainer != m_Container || originSection != GetSection()) - && !m_Container.HasVisibleOverlays(GetSection()) + return !m_Container.HasVisibleOverlays(GetSection()) && !m_Container.ContainsOverlay(draggedOverlay, GetSection()); } diff --git a/Editor/Mono/Overlays/OverlayDockArea.cs b/Editor/Mono/Overlays/OverlayDockArea.cs index 6c8e0fb659..be106a41ef 100644 --- a/Editor/Mono/Overlays/OverlayDockArea.cs +++ b/Editor/Mono/Overlays/OverlayDockArea.cs @@ -9,6 +9,18 @@ namespace UnityEditor.Overlays { sealed class OverlayDockArea : VisualElement { + // Used in tests. + internal const string topToolbarDropZone = "DropZone-TopToolbar"; + internal const string bottomToolbarDropZone = "DropZone-BottomToolbar"; + internal const string leftToolbarDropZone = "DropZone-LeftToolbar"; + internal const string rightToolbarDropZone = "DropZone-RightToolbar"; + + // Used in tests. + internal const string topLeftColumnDropZone = "DropZone-TopLeftColumn"; + internal const string bottomLeftColumnDropZone = "DropZone-BottomLeftColumn"; + internal const string topRightColumnDropZone = "DropZone-TopRightColumn"; + internal const string bottomRightColumnDropZone = "DropZone-BottomRightColumn"; + readonly ToolbarDropZone m_TopToolbar; readonly ToolbarDropZone m_BottomToolbar; readonly ToolbarDropZone m_LeftToolbar; @@ -24,14 +36,14 @@ public OverlayDockArea(OverlayCanvas canvas) style.position = Position.Absolute; pickingMode = PickingMode.Ignore; - Add(m_TopToolbar = new ToolbarDropZone(canvas.GetDockZoneContainer(DockZone.TopToolbar)) { name = "DropZone-TopToolbar" }); - Add(m_BottomToolbar = new ToolbarDropZone(canvas.GetDockZoneContainer(DockZone.BottomToolbar)) { name = "DropZone-BottomToolbar" }); - Add(m_LeftToolbar = new ToolbarDropZone(canvas.GetDockZoneContainer(DockZone.LeftToolbar)) { name = "DropZone-LeftToolbar" }); - Add(m_RightToolbar = new ToolbarDropZone(canvas.GetDockZoneContainer(DockZone.RightToolbar)) { name = "DropZone-RightToolbar" }); - Add(m_TopLeftColumn = new OverlayContainerDropZone(canvas.GetDockZoneContainer(DockZone.LeftColumn), OverlayContainerDropZone.Placement.Start, m_TopToolbar, m_LeftToolbar) { name = "DropZone-TopLeftColumn" }); - Add(m_BottomLeftColumn = new OverlayContainerDropZone(canvas.GetDockZoneContainer(DockZone.LeftColumn), OverlayContainerDropZone.Placement.End, m_BottomToolbar, m_LeftToolbar) { name = "DropZone-BottomLeftColumn" }); - Add(m_TopRightColumn = new OverlayContainerDropZone(canvas.GetDockZoneContainer(DockZone.RightColumn), OverlayContainerDropZone.Placement.Start, m_TopToolbar, m_RightToolbar) { name = "DropZone-TopRightColumn" }); - Add(m_BottomRightColumn = new OverlayContainerDropZone(canvas.GetDockZoneContainer(DockZone.RightColumn), OverlayContainerDropZone.Placement.End, m_BottomToolbar, m_RightToolbar) { name = "DropZone-BottomRightColumn" }); + Add(m_TopToolbar = new ToolbarDropZone(canvas.GetDockZoneContainer(DockZone.TopToolbar)) { name = topToolbarDropZone }); + Add(m_BottomToolbar = new ToolbarDropZone(canvas.GetDockZoneContainer(DockZone.BottomToolbar)) { name = bottomToolbarDropZone }); + Add(m_LeftToolbar = new ToolbarDropZone(canvas.GetDockZoneContainer(DockZone.LeftToolbar)) { name = leftToolbarDropZone }); + Add(m_RightToolbar = new ToolbarDropZone(canvas.GetDockZoneContainer(DockZone.RightToolbar)) { name = rightToolbarDropZone }); + Add(m_TopLeftColumn = new OverlayContainerDropZone(canvas.GetDockZoneContainer(DockZone.LeftColumn), OverlayContainerDropZone.Placement.Start, m_TopToolbar, m_LeftToolbar) { name = topLeftColumnDropZone }); + Add(m_BottomLeftColumn = new OverlayContainerDropZone(canvas.GetDockZoneContainer(DockZone.LeftColumn), OverlayContainerDropZone.Placement.End, m_BottomToolbar, m_LeftToolbar) { name = bottomLeftColumnDropZone }); + Add(m_TopRightColumn = new OverlayContainerDropZone(canvas.GetDockZoneContainer(DockZone.RightColumn), OverlayContainerDropZone.Placement.Start, m_TopToolbar, m_RightToolbar) { name = topRightColumnDropZone }); + Add(m_BottomRightColumn = new OverlayContainerDropZone(canvas.GetDockZoneContainer(DockZone.RightColumn), OverlayContainerDropZone.Placement.End, m_BottomToolbar, m_RightToolbar) { name = bottomRightColumnDropZone }); } public IEnumerable GetDropZones() diff --git a/Editor/Mono/Overlays/OverlayDragger.cs b/Editor/Mono/Overlays/OverlayDragger.cs index 0f742380f3..417139664d 100644 --- a/Editor/Mono/Overlays/OverlayDragger.cs +++ b/Editor/Mono/Overlays/OverlayDragger.cs @@ -78,10 +78,18 @@ public void UpdateHover(OverlayDropZoneBase hovered) m_Hovered = hovered; - //Remove dropzone f we have a different container - if (m_Hovered == null || m_Hovered.targetContainer != m_OriginContainer) - m_OriginGhostDropZone?.RemoveFromHierarchy(); - + // Remove dropzone if we have a different container + if ((m_Hovered == null || m_Hovered.targetContainer != m_OriginContainer) + && m_OriginGhostDropZone != null && !(m_OriginGhostDropZone.targetContainer is ToolbarOverlayContainer)) + { + m_OriginGhostDropZone.RemoveFromHierarchy(); + foreach (var dropZone in m_DropZones) + { + if (dropZone.targetContainer == m_OriginContainer) + dropZone.Activate(m_TargetOverlay); + } + } + if (m_Hovered != null) m_Hovered.BeginHover(); @@ -236,7 +244,7 @@ void OnMouseMove(MouseMoveEvent e) if (delayPositionUpdate) m_Overlay.rootVisualElement.RegisterCallback(DelayedPositionUpdate, targetRect); - else + else m_Overlay.rootVisualElement.transform.position = OverlayUtilities.ClampRectToRect(targetRect, floatingContainer.rect).position; m_DockOperation.UpdateHover(dropZone); @@ -267,7 +275,7 @@ void OnMouseUp(MouseUpEvent e) { CancelDrag(); return; - } + } m_Overlay.container?.RemoveOverlay(m_Overlay); m_Overlay.rootVisualElement.transform.position = Vector2.zero; diff --git a/Editor/Mono/Overlays/OverlayDropZone.cs b/Editor/Mono/Overlays/OverlayDropZone.cs index 6cb730cbe3..cb73659dc2 100644 --- a/Editor/Mono/Overlays/OverlayDropZone.cs +++ b/Editor/Mono/Overlays/OverlayDropZone.cs @@ -78,7 +78,7 @@ public override void EndHover() public override void DropOverlay(Overlay overlay) { - + m_TargetOverlay.container.GetOverlayIndex(m_TargetOverlay, out var section, out _); if (ShouldDockAfter(section)) { diff --git a/Editor/Mono/Overlays/OverlayDropZoneBase.cs b/Editor/Mono/Overlays/OverlayDropZoneBase.cs index 59b6389527..ae9e18ea17 100644 --- a/Editor/Mono/Overlays/OverlayDropZoneBase.cs +++ b/Editor/Mono/Overlays/OverlayDropZoneBase.cs @@ -10,7 +10,7 @@ abstract class OverlayDropZoneBase : VisualElement { public const string className = "unity-overlay-drop-zone"; const string k_HoveredState = "unity-overlay-drop-zone--hovered"; - const string k_HiddenState = "unity-overlay-drop-zone--hidden"; + internal const string hiddenState = "unity-overlay-drop-zone--hidden"; // Used in tests. protected OverlayInsertIndicator insertIndicator { get; private set; } protected OverlayContainer originContainer { get; private set; } @@ -76,13 +76,13 @@ public bool HasSameTargetContainer(OverlayDropZoneBase dropZone) protected void SetHidden(bool hidden) { - EnableInClassList(k_HiddenState, hidden); + EnableInClassList(hiddenState, hidden); } public virtual void Deactivate(Overlay draggedOverlay) { visible = false; - pickingMode = PickingMode.Ignore; + pickingMode = PickingMode.Ignore; } } } diff --git a/Editor/Mono/Overlays/ToolbarDropZone.cs b/Editor/Mono/Overlays/ToolbarDropZone.cs index f8d683b84b..25b2403747 100644 --- a/Editor/Mono/Overlays/ToolbarDropZone.cs +++ b/Editor/Mono/Overlays/ToolbarDropZone.cs @@ -10,7 +10,7 @@ public ToolbarDropZone(OverlayContainer container) : base(container, Placement.S protected override bool ShouldEnable(Overlay draggedOverlay) { - return targetContainer != originContainer && !targetContainer.HasVisibleOverlays(); + return !targetContainer.HasVisibleOverlays(); } public override void Activate(Overlay draggedOverlay) diff --git a/Editor/Mono/PlayModeView/PlayModeView.cs b/Editor/Mono/PlayModeView/PlayModeView.cs index b48b508af1..09ae86eeb7 100644 --- a/Editor/Mono/PlayModeView/PlayModeView.cs +++ b/Editor/Mono/PlayModeView/PlayModeView.cs @@ -341,6 +341,7 @@ protected internal void SwapMainWindow(Type type) DestroyImmediate(this, true); } } + RemoveDisabledWindows(); } private void ClearTargetTexture() diff --git a/Editor/Mono/PlayerSettings.bindings.cs b/Editor/Mono/PlayerSettings.bindings.cs index 3a155e7197..4ae31c18b2 100644 --- a/Editor/Mono/PlayerSettings.bindings.cs +++ b/Editor/Mono/PlayerSettings.bindings.cs @@ -369,7 +369,7 @@ internal static void ValidateBuildTargetNameParameter(string buildTargetName, bo internal static SerializedObject GetSerializedObject() { - if (_serializedObject == null) + if (_serializedObject == null || _serializedObject.targetObject != InternalGetPlayerSettingsObject()) _serializedObject = new SerializedObject(InternalGetPlayerSettingsObject()); return _serializedObject; } @@ -1756,6 +1756,18 @@ internal static extern bool iosCopyPluginsCodeInsteadOfSymlink set; } + [StaticAccessor("PlayerSettings", StaticAccessorType.DoubleColon)] + internal static extern void SetOverridePlayerSettingsInternal(PlayerSettings playerSettings); + + [StaticAccessor("PlayerSettings", StaticAccessorType.DoubleColon)] + internal static extern bool IsGlobalManagerPlayerSettings(PlayerSettings playerSettings); + + [StaticAccessor("PlayerSettings", StaticAccessorType.DoubleColon)] + internal static extern string SerializeAsYAMLString(PlayerSettings playerSettings); + + [StaticAccessor("PlayerSettings", StaticAccessorType.DoubleColon)] + internal static extern PlayerSettings DeserializeFromYAMLString(string yamlSettings); + internal static extern bool platformRequiresReadableAssets { get; set; } } } diff --git a/Editor/Mono/PlayerSettingsAndroid.bindings.cs b/Editor/Mono/PlayerSettingsAndroid.bindings.cs index 15d2b01f49..227efa0715 100644 --- a/Editor/Mono/PlayerSettingsAndroid.bindings.cs +++ b/Editor/Mono/PlayerSettingsAndroid.bindings.cs @@ -23,6 +23,7 @@ public enum AndroidArchitecture : uint ARM64 = 1 << 1, // x86 + [Obsolete("X86 is no longer supported.")] X86 = 1 << 2, // x86_64 @@ -33,6 +34,7 @@ public enum AndroidArchitecture : uint } // Target devices. + [Obsolete("AndroidTargetDevices is deprecated since ChromeOS is no longer supported.")] public enum AndroidTargetDevices { // All devices. The Android aplication is allowed to run on all devices. @@ -360,8 +362,8 @@ public static extern bool forceSDCardPermission // Gamepad support level for Android TV internal static extern AndroidGamepadSupportLevel androidGamepadSupportLevel { get; set; } - // Disable Chrome OS's default behaviour of converting mouse and touchpad input events into touchscreen input events. - public static extern bool chromeosInputEmulation { get; set; } + [Obsolete("ChromeOS is no longer supported.")] + public static bool chromeosInputEmulation { get; set; } // Returns Android banner list internal static extern AndroidBanner[] GetAndroidBanners(); @@ -418,7 +420,8 @@ public static extern bool buildApkPerCpuArchitecture set; } - public static extern AndroidTargetDevices androidTargetDevices { get; set; } + [Obsolete("androidTargetDevices is deprecated since ChromeOS is no longer supported.")] + public static AndroidTargetDevices androidTargetDevices { get; set; } [StaticAccessor("GetPlayerSettings().GetEditorOnly()", StaticAccessorType.Dot)] [NativeProperty("androidSplashScreen", TargetType.Field)] diff --git a/Editor/Mono/PlayerSettingsIOS.bindings.cs b/Editor/Mono/PlayerSettingsIOS.bindings.cs index 0a9e34d235..eb531dcde5 100644 --- a/Editor/Mono/PlayerSettingsIOS.bindings.cs +++ b/Editor/Mono/PlayerSettingsIOS.bindings.cs @@ -19,6 +19,7 @@ namespace UnityEditor { // AppleMobile CPU architecture. // Matches enum in EditorOnlyPlayerSettings.h. + // For Device [Flags] public enum AppleMobileArchitecture : uint { @@ -30,6 +31,14 @@ public enum AppleMobileArchitecture : uint Universal = 1 << 1 } + // For Simulator + public enum AppleMobileArchitectureSimulator + { + X86_64 = 0, + ARM64 = 1 << 0, + Universal = 1 << 1 + } + // Supported iOS SDK versions public enum iOSSdkVersion { @@ -268,12 +277,13 @@ private extern static int scriptCallOptimizationInternal [NativeMethod("SetiPhoneScriptCallOptimization")] set; } - public static ScriptCallOptimizationLevel scriptCallOptimization { get { return (ScriptCallOptimizationLevel)scriptCallOptimizationInternal; } set { scriptCallOptimizationInternal = (int)value; } } + + // Active iOS SDK version used for build private extern static int sdkVersionInternal { [NativeMethod("GetiPhoneSdkVersion")] @@ -281,14 +291,26 @@ private extern static int sdkVersionInternal [NativeMethod("SetiPhoneSdkVersion")] set; } - - // Active iOS SDK version used for build public static iOSSdkVersion sdkVersion { get { return (iOSSdkVersion)sdkVersionInternal; } set { sdkVersionInternal = (int)value; } } + // Simulator Architectures + private extern static int simulatorSdkArchitectureInternal + { + [NativeMethod("GetiOSSimulatorArchitecture")] + get; + [NativeMethod("SetiOSSimulatorArchitecture")] + set; + } + public static AppleMobileArchitectureSimulator simulatorSdkArchitecture + { + get { return (AppleMobileArchitectureSimulator)simulatorSdkArchitectureInternal; } + set { simulatorSdkArchitectureInternal = (int)value; } + } + [FreeFunction] private extern static string iOSTargetOSVersionObsoleteEnumToString(int val); diff --git a/Editor/Mono/PlayerSettingsTVOS.bindings.cs b/Editor/Mono/PlayerSettingsTVOS.bindings.cs index df0bf886fd..848ccbf088 100644 --- a/Editor/Mono/PlayerSettingsTVOS.bindings.cs +++ b/Editor/Mono/PlayerSettingsTVOS.bindings.cs @@ -33,6 +33,7 @@ public partial class PlayerSettings : UnityEngine.Object [StaticAccessor("GetPlayerSettings()")] public partial class tvOS { + // Sdk Version private static extern int sdkVersionInt { [NativeMethod("GettvOSSdkVersion")] @@ -40,13 +41,26 @@ private static extern int sdkVersionInt [NativeMethod("SettvOSSdkVersion")] set; } - public static tvOSSdkVersion sdkVersion { get { return (tvOSSdkVersion)sdkVersionInt; } set { sdkVersionInt = (int)value; } } + // Simulator Architectures + private extern static int simulatorSdkArchitectureInternal + { + [NativeMethod("GettvOSSimulatorArchitecture")] + get; + [NativeMethod("SettvOSSimulatorArchitecture")] + set; + } + public static AppleMobileArchitectureSimulator simulatorSdkArchitecture + { + get { return (AppleMobileArchitectureSimulator)simulatorSdkArchitectureInternal; } + set { simulatorSdkArchitectureInternal = (int)value; } + } + // tvOS bundle build number public static string buildNumber { diff --git a/Editor/Mono/PlayerSettingsWSA.bindings.cs b/Editor/Mono/PlayerSettingsWSA.bindings.cs index 9f128819ce..675d18c064 100644 --- a/Editor/Mono/PlayerSettingsWSA.bindings.cs +++ b/Editor/Mono/PlayerSettingsWSA.bindings.cs @@ -338,6 +338,16 @@ private static extern Color splashScreenBackgroundColorRaw set; } + [NativeProperty("syncCapabilities", TargetType.Field)] + public static extern bool syncCapabilities + { + [StaticAccessor("GetPlayerSettings().GetEditorOnly()", StaticAccessorType.Dot)] + get; + + [StaticAccessor("GetPlayerSettings().GetEditorOnlyForUpdate()", StaticAccessorType.Dot)] + set; + } + private static extern void InternalSetCapability(string name, string value); private static extern string InternalGetCapability(string name); diff --git a/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesTreeView.cs b/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesTreeView.cs index d7613b32bf..a852336403 100644 --- a/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesTreeView.cs +++ b/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesTreeView.cs @@ -7,8 +7,10 @@ using System.Collections.Generic; using UnityEditor.IMGUI.Controls; using UnityEditor.SceneManagement; +using UnityEditor.UIElements; +using UnityEngine.UIElements; using Object = UnityEngine.Object; - +using TreeView = UnityEditor.IMGUI.Controls.TreeView; namespace UnityEditor { @@ -613,23 +615,22 @@ class ComparisonViewPopup : PopupWindowContent readonly PrefabOverride m_Modification; readonly Object m_Source; readonly Object m_Instance; - readonly Editor m_SourceEditor; - readonly Editor m_InstanceEditor; readonly bool m_Unappliable; - const float k_HeaderHeight = 25f; - const float k_ScrollbarWidth = 13; - Vector2 m_PreviewSize = new Vector2(600f, 0); - Vector2 m_Scroll; - bool m_RenderOverlayAfterResizeChange; bool m_OwnerNeedsRefresh; static class Styles { - public static GUIStyle borderStyle = new GUIStyle("grey_border"); - public static GUIStyle centeredLabelStyle = new GUIStyle(EditorStyles.label); + public const string ussPath = "StyleSheets/Prefab/ComparisonViewPopup.uss"; + public const string rootClass = "unity-prefab-compare__root"; + public const string dualViewClass = "unity-prefab-compare-dual"; + public const string headerClass = "unity-prefab-compare__header"; + public const string cellClass = "unity-prefab-compare__cell"; + public const string contentClass = "unity-prefab-compare__content"; + public const string rightClass = "unity-prefab-compare__right"; + public const string headerButtonClass = "unity-prefab-compare__header-buttons"; + public static GUIStyle headerGroupStyle = new GUIStyle(); - public static GUIStyle headerStyle = new GUIStyle(EditorStyles.boldLabel); public static GUIContent sourceContent = EditorGUIUtility.TrTextContent("Prefab Source"); public static GUIContent instanceContent = EditorGUIUtility.TrTextContent("Override"); public static GUIContent removedContent = EditorGUIUtility.TrTextContent("Removed"); @@ -640,14 +641,7 @@ static class Styles static Styles() { - centeredLabelStyle.alignment = TextAnchor.UpperCenter; - centeredLabelStyle.padding = new RectOffset(3, 3, 3, 3); - headerGroupStyle.padding = new RectOffset(0, 0, 3, 3); - - headerStyle.alignment = TextAnchor.MiddleLeft; - headerStyle.padding.left = 5; - headerStyle.padding.top = 1; } } @@ -658,25 +652,9 @@ public ComparisonViewPopup(Object source, Object instance, PrefabOverride modifi m_Instance = instance; m_Modification = modification; if (modification != null) - { m_Unappliable = !PrefabUtility.IsPartOfPrefabThatCanBeAppliedTo(modification.GetAssetObject()); - } else - { m_Unappliable = false; - } - - if (m_Source != null) - { - m_SourceEditor = Editor.CreateEditor(m_Source); - } - if (m_Instance != null) - { - m_InstanceEditor = Editor.CreateEditor(m_Instance); - } - - if (m_Source == null || m_Instance == null || m_Modification == null) - m_PreviewSize.x /= 2; if (modification is ObjectOverride) Undo.postprocessModifications += RecheckOverrideStatus; @@ -686,12 +664,7 @@ public override void OnClose() { Undo.postprocessModifications -= RecheckOverrideStatus; m_Owner.ComparisonPopupClosed(m_Instance, m_OwnerNeedsRefresh); - base.OnClose(); - if (m_SourceEditor != null) - Object.DestroyImmediate(m_SourceEditor); - if (m_InstanceEditor != null) - Object.DestroyImmediate(m_InstanceEditor); } UndoPropertyModification[] RecheckOverrideStatus(UndoPropertyModification[] modifications) @@ -714,125 +687,118 @@ void UpdateAndCloseOnNextTick() UpdateAndClose(); } - bool UpdatePreviewHeight(float height) + public override VisualElement CreateGUI() { - if (height > 0 && m_PreviewSize.y != height) - { - m_PreviewSize.y = height; - return true; - } - return false; - } + var root = new VisualElement(); + root.AddStyleSheetPath(Styles.ussPath); + root.AddToClassList(Styles.rootClass); + if (m_Modification != null && m_Source != null && m_Instance != null) + root.AddToClassList(Styles.dualViewClass); - public override void OnGUI(Rect rect) - { - bool scroll = (m_PreviewSize.y > rect.height - k_HeaderHeight); - if (scroll) - rect.width -= k_ScrollbarWidth + 1; - else - // We overdraw border by one pixel to the right, so subtract here to account for that. - rect.width -= 1; + root.Add(CreateHeader()); + + if (m_Modification != null) + root.Add(CreateComparisonView()); - EditorGUIUtility.wideMode = true; - EditorGUIUtility.labelWidth = 120; - int middleCol = Mathf.RoundToInt((rect.width - 1) * 0.5f); + return root; + } - if (Event.current.type == EventType.Repaint) - EditorStyles.viewBackground.Draw(rect, GUIContent.none, 0); + VisualElement CreateHeader() + { + var container = new VisualElement(); + container.AddToClassList(Styles.headerClass); if (m_Modification == null) { - DrawHeader( - new Rect(rect.x, rect.y, rect.width, k_HeaderHeight), - Styles.noModificationsContent); - m_PreviewSize.y = 0; - return; + container.Add(CreateHeaderCell(Styles.noModificationsContent.text)); + return container; } - Rect scrollRectPosition = - new Rect( - rect.x, - rect.y + k_HeaderHeight, - rect.width + (scroll ? k_ScrollbarWidth : 0), - rect.height - k_HeaderHeight); - Rect viewPosition = new Rect(0, 0, rect.width, m_PreviewSize.y); - if (m_Source != null && m_Instance != null) { - Rect sourceHeaderRect = new Rect(rect.x, rect.y, middleCol, k_HeaderHeight); - Rect instanceHeaderRect = new Rect(rect.x + middleCol, rect.y, rect.xMax - middleCol + (scroll ? k_ScrollbarWidth : 0), k_HeaderHeight); - DrawHeader(sourceHeaderRect, Styles.sourceContent); - DrawHeader(instanceHeaderRect, Styles.instanceContent); - - DrawRevertApplyButtons(instanceHeaderRect); + var sourceHeader = CreateHeaderCell(Styles.sourceContent.text); + var instanceHeader = CreateHeaderCell(Styles.instanceContent.text); + instanceHeader.AddToClassList(Styles.rightClass); + instanceHeader.Add(CreateHeaderButtons()); - m_Scroll = GUI.BeginScrollView(scrollRectPosition, m_Scroll, viewPosition); - { - var leftColumnHeight = DrawEditor(new Rect(0, 0, middleCol, m_PreviewSize.y), m_SourceEditor, true, EditorGUIUtility.ComparisonViewMode.Original); - - var rightColumnHeight = DrawEditor(new Rect(middleCol, 0, rect.xMax - middleCol, m_PreviewSize.y), m_InstanceEditor, false, EditorGUIUtility.ComparisonViewMode.Modified); - - if (UpdatePreviewHeight(Math.Max(leftColumnHeight, rightColumnHeight))) - m_RenderOverlayAfterResizeChange = true; - } - GUI.EndScrollView(); + container.Add(sourceHeader); + container.Add(instanceHeader); } else { - GUIContent headerContent; - Editor editor; - bool disable; - if (m_Source != null) - { - headerContent = Styles.removedContent; - editor = m_SourceEditor; - disable = true; - } - else - { - headerContent = Styles.addedContent; - editor = m_InstanceEditor; - disable = false; - } + string headerContentText = m_Source != null ? Styles.removedContent.text : Styles.addedContent.text; + var header = CreateHeaderCell(headerContentText); + header.Add(CreateHeaderButtons()); + container.Add(header); + } - Rect headerRect = new Rect(rect.x, rect.y, rect.width, k_HeaderHeight); - DrawHeader(headerRect, headerContent); + return container; + } - DrawRevertApplyButtons(headerRect); + VisualElement CreateHeaderButtons() + { + var container = new IMGUIContainer(DrawRevertApplyButtons); + container.AddToClassList(Styles.headerButtonClass); + return container; + } - m_Scroll = GUI.BeginScrollView(scrollRectPosition, m_Scroll, viewPosition); + VisualElement CreateComparisonView() + { + var comparisonView = new ScrollView + { + mode = ScrollViewMode.Vertical, + verticalScrollerVisibility = ScrollerVisibility.AlwaysVisible + }; + comparisonView.RegisterCallback(OnObjectChanged); - float columnHeight = DrawEditor(new Rect(0, 0, rect.width, m_PreviewSize.y), editor, disable, EditorGUIUtility.ComparisonViewMode.Modified); - if (UpdatePreviewHeight(columnHeight)) - m_RenderOverlayAfterResizeChange = true; + if (m_Source != null && m_Instance != null) + comparisonView.Add(CreateDualObjectView()); + else + comparisonView.Add(CreateSingleObjectView()); - GUI.EndScrollView(); - } + return comparisonView; + } - if (m_RenderOverlayAfterResizeChange && Event.current.type == EventType.Repaint) + void OnObjectChanged(SerializedObjectChangeEvent obj) + { + m_OwnerNeedsRefresh = true; + } + + VisualElement CreateSingleObjectView() + { + if (m_Source != null) + { + var inspector = CreateObjectInspector(m_Source, EditorGUIUtility.ComparisonViewMode.Original); + inspector.enabledSelf = false; + return inspector; + } + else { - m_RenderOverlayAfterResizeChange = false; - // The comparison view resizes a frame delayed due to having to wait for the first render to - // layout the contents. This creates a distorted rendering because the last frame rendered is rendered - // to the new window size. We therefore 'clear' the comparison view after a resize change by rendering - // a quad on top with the background color so the distorted rendering is not shown to the user. - // Fixes case 1069062. - GUI.Label(rect, GUIContent.none, EditorStyles.viewBackground); - editorWindow.Repaint(); + var inspector = CreateObjectInspector(m_Instance, EditorGUIUtility.ComparisonViewMode.Original); + inspector.enabledSelf = true; + return inspector; } } - void DrawHeader(Rect rect, GUIContent label) + VisualElement CreateDualObjectView() { - EditorGUI.LabelField(rect, label, Styles.headerStyle); - // Overdraw border by one pixel to the right, so adjacent borders overlap. - // Don't overdraw down, since overlapping scroll view can make controls overlap divider line. - GUI.Label(new Rect(rect.x, rect.y, rect.width + 1, rect.height), GUIContent.none, Styles.borderStyle); + var sourceInspector = CreateObjectInspector(m_Source, EditorGUIUtility.ComparisonViewMode.Original); + var instanceInspector = CreateObjectInspector(m_Instance, EditorGUIUtility.ComparisonViewMode.Modified); + + sourceInspector.enabledSelf = false; + sourceInspector.AddToClassList(Styles.cellClass); + instanceInspector.AddToClassList(Styles.cellClass); + instanceInspector.AddToClassList(Styles.rightClass); + + var container = new VisualElement(); + container.AddToClassList(Styles.contentClass); + container.Add(sourceInspector); + container.Add(instanceInspector); + return container; } - void DrawRevertApplyButtons(Rect rect) + void DrawRevertApplyButtons() { - GUILayout.BeginArea(rect); GUILayout.BeginHorizontal(Styles.headerGroupStyle); GUILayout.FlexibleSpace(); @@ -855,7 +821,6 @@ void DrawRevertApplyButtons(Rect rect) } GUILayout.EndHorizontal(); - GUILayout.EndArea(); } void Apply(object prefabAssetPathObject) @@ -875,61 +840,37 @@ void UpdateAndClose() editorWindow?.Close(); } - float DrawEditor(Rect rect, Editor editor, bool disabled, EditorGUIUtility.ComparisonViewMode comparisonViewMode) + static VisualElement CreateObjectInspector(Object obj, EditorGUIUtility.ComparisonViewMode viewMode) { - rect.xMin += 1; - EditorGUIUtility.ResetGUIState(); - - EditorGUIUtility.wideMode = true; - EditorGUIUtility.labelWidth = 120; - EditorGUIUtility.comparisonViewMode = comparisonViewMode; - EditorGUIUtility.leftMarginCoord = rect.x; - - GUILayout.BeginArea(rect); - Rect editorRect = EditorGUILayout.BeginVertical(); - { - using (new EditorGUI.DisabledScope(disabled)) - { - if (editor == null) - { - GUI.enabled = true; - GUILayout.Label("None - this should not happen.", Styles.centeredLabelStyle); - } - else - { - EditorGUI.BeginChangeCheck(); - if (editor.target is GameObject) - { - editor.DrawHeader(); - } - else - { - EditorGUIUtility.hierarchyMode = true; - EditorGUILayout.InspectorTitlebar(true, editor); - EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins); - editor.OnInspectorGUI(); - EditorGUILayout.Space(); - EditorGUILayout.EndVertical(); - } - - if (EditorGUI.EndChangeCheck()) - m_OwnerNeedsRefresh = true; - } - } - } + var container = new VisualElement(); + var inspector = new InspectorElement(obj) { comparisonViewMode = viewMode }; + if (inspector.boundObject != null) + inspector.TrackSerializedObjectValue(inspector.boundObject); - EditorGUILayout.EndVertical(); - GUILayout.EndArea(); - - // Overdraw border by one pixel in all directions. - GUI.Label(new Rect(rect.x - 1, -1, rect.width + 2, m_PreviewSize.y + 2), GUIContent.none, Styles.borderStyle); + container.Add(new IMGUIContainer(() => DrawObjectHeader(inspector.editor, viewMode))); + container.Add(inspector); + return container; + } - return editorRect.height; + static VisualElement CreateHeaderCell(string label) + { + var headerCell = new VisualElement(); + headerCell.AddToClassList(Styles.cellClass); + headerCell.Add(new Label(label)); + return headerCell; } - public override Vector2 GetWindowSize() + static void DrawObjectHeader(Editor editor, EditorGUIUtility.ComparisonViewMode viewMode) { - return new Vector2(m_PreviewSize.x, m_PreviewSize.y + k_HeaderHeight + 1f); + if (editor == null) return; + if (editor.target is GameObject) + editor.DrawHeader(); + else + { + EditorGUIUtility.comparisonViewMode = viewMode; + EditorGUIUtility.hierarchyMode = true; + EditorGUILayout.InspectorTitlebar(true, editor); + } } } } diff --git a/Editor/Mono/Prefabs/PrefabUtility.cs b/Editor/Mono/Prefabs/PrefabUtility.cs index 7819e1ab34..7dd98d296a 100644 --- a/Editor/Mono/Prefabs/PrefabUtility.cs +++ b/Editor/Mono/Prefabs/PrefabUtility.cs @@ -2946,38 +2946,38 @@ internal static bool HasInvalidComponent(GameObject rootOfSearch) return FindGameObjectsWithInvalidComponent(rootOfSearch).Count > 0; } - internal static bool HasInvalidComponent(Object gameObjectOrComponent) + internal static bool HasInvalidComponent(Object componentOrGameObject) { - if (gameObjectOrComponent == null) + if (componentOrGameObject == null) return true; - if (gameObjectOrComponent is Component) + if (componentOrGameObject is Component) { - Component comp = (Component)gameObjectOrComponent; - gameObjectOrComponent = (GameObject)comp.gameObject; + Component comp = (Component)componentOrGameObject; + componentOrGameObject = (GameObject)comp.gameObject; } - if (!(gameObjectOrComponent is GameObject)) + if (!(componentOrGameObject is GameObject)) return false; - return HasInvalidComponent((GameObject)gameObjectOrComponent); + return HasInvalidComponent((GameObject)componentOrGameObject); } - public static bool IsPartOfPrefabThatCanBeAppliedTo(Object gameObjectOrComponent) + public static bool IsPartOfPrefabThatCanBeAppliedTo(Object componentOrGameObject) { - if (gameObjectOrComponent == null) + if (componentOrGameObject == null) return false; - if (IsPartOfImmutablePrefab(gameObjectOrComponent)) + if (IsPartOfImmutablePrefab(componentOrGameObject)) return false; - if (!EditorUtility.IsPersistent(gameObjectOrComponent)) - gameObjectOrComponent = GetCorrespondingObjectFromSource(gameObjectOrComponent); + if (!EditorUtility.IsPersistent(componentOrGameObject)) + componentOrGameObject = GetCorrespondingObjectFromSource(componentOrGameObject); - if (HasInvalidComponent(gameObjectOrComponent)) + if (HasInvalidComponent(componentOrGameObject)) return false; - if (PrefabUtility.HasManagedReferencesWithMissingTypes(gameObjectOrComponent)) + if (PrefabUtility.HasManagedReferencesWithMissingTypes(componentOrGameObject)) return false; return true; diff --git a/Editor/Mono/PreferencesWindow/PreferencesSettingsProviders.cs b/Editor/Mono/PreferencesWindow/PreferencesSettingsProviders.cs index 8c735b1e3b..7947e13562 100644 --- a/Editor/Mono/PreferencesWindow/PreferencesSettingsProviders.cs +++ b/Editor/Mono/PreferencesWindow/PreferencesSettingsProviders.cs @@ -88,7 +88,10 @@ class GeneralProperties public static readonly GUIContent enableExtendedLogging = EditorGUIUtility.TrTextContent("Timestamp Editor log entries", "Adds timestamp and thread Id to Editor.log messages."); public static readonly GUIContent enableHelperBar = EditorGUIUtility.TrTextContent("Enable Helper Bar", "Enables Helper Bar in the status bar at the bottom of the main Unity Editor window."); public static readonly GUIContent enablePlayModeTooltips = EditorGUIUtility.TrTextContent("Enable PlayMode Tooltips", "Enables tooltips in the editor while in play mode."); - public static readonly GUIContent showSecondaryWindowsInTaskbar = EditorGUIUtility.TrTextContent("Show All Windows in Taskbar"); + public static readonly GUIContent showSecondaryWindowsInTaskbar = EditorGUIUtility.TrTextContent("Show All Windows in Taskbar", + @"Enabling this setting allows undocked windows to be minimized in the OS taskbar. +By default, Windows will combine these under a single taskbar item."); + public static readonly GUIContent useProjectPathInTitle = EditorGUIUtility.TrTextContent("Use Project Path in Window Title", "If enabled the Project's name is replaced in the main window title with the Project's path on disk."); } diff --git a/Editor/Mono/ProjectBrowser/ProjectBrowser.cs b/Editor/Mono/ProjectBrowser/ProjectBrowser.cs index 74f287cc2f..65ae0a97f6 100644 --- a/Editor/Mono/ProjectBrowser/ProjectBrowser.cs +++ b/Editor/Mono/ProjectBrowser/ProjectBrowser.cs @@ -21,7 +21,7 @@ namespace UnityEditor { // The title is also used for fetching the project window tab icon: Project.png [EditorWindowTitle(title = "Project", icon = "Project")] - internal class ProjectBrowser : EditorWindow, IHasCustomMenu + internal class ProjectBrowser : EditorWindow, IHasCustomMenu, ISearchableContainer { public const int kPackagesFolderInstanceId = int.MaxValue; public const int kAssetCreationInstanceID_ForNonExistingAssets = Int32.MaxValue - 1; @@ -135,6 +135,8 @@ internal bool isLocked set { m_LockTracker.isLocked = value; } } + public string searchText => m_SearchFieldText; + bool m_EnableOldAssetTree = true; bool m_FocusSearchField; string m_SelectedPath; @@ -1584,10 +1586,10 @@ void InitListArea() m_SearchFilter.skipHidden = m_SkipHiddenPackages; - m_ListArea.InitForSearch(m_ListAreaRect, HierarchyType.Assets, + m_ListArea?.InitForSearch(m_ListAreaRect, HierarchyType.Assets, m_SearchFilter, false, s => AssetDatabase.GetMainAssetInstanceID(s)); - m_ListArea.InitSelection(Selection.instanceIDs); + m_ListArea?.InitSelection(Selection.instanceIDs); } void OnInspectorUpdate() diff --git a/Editor/Mono/SceneHierarchyWindow.cs b/Editor/Mono/SceneHierarchyWindow.cs index 08a842e864..09f7c1f079 100644 --- a/Editor/Mono/SceneHierarchyWindow.cs +++ b/Editor/Mono/SceneHierarchyWindow.cs @@ -12,7 +12,7 @@ namespace UnityEditor { [EditorWindowTitle(title = "Hierarchy", useTypeNameAsIconName = true)] - internal class SceneHierarchyWindow : SearchableEditorWindow, IHasCustomMenu, IPropertySourceOpener + internal class SceneHierarchyWindow : SearchableEditorWindow, IHasCustomMenu, IPropertySourceOpener, ISearchableContainer { public static SceneHierarchyWindow lastInteractedHierarchyWindow { get { return s_LastInteractedHierarchy; } } static SceneHierarchyWindow s_LastInteractedHierarchy; @@ -38,6 +38,8 @@ static class Styles bool showingStageHeader { get { return !(StageNavigationManager.instance.currentStage is MainStage); } } + public string searchText => m_SearchFilter; + void Awake() { m_HierarchyType = HierarchyType.GameObjects; diff --git a/Editor/Mono/SceneView/SceneView.cs b/Editor/Mono/SceneView/SceneView.cs index 1c6b34996f..ecd12be98f 100644 --- a/Editor/Mono/SceneView/SceneView.cs +++ b/Editor/Mono/SceneView/SceneView.cs @@ -1709,6 +1709,7 @@ void RefreshAudioPlay() if (s_AudioSceneView.m_PlayAudio) { s_AudioSceneView.m_PlayAudio = false; + s_AudioSceneView.sceneAudioChanged?.Invoke(false); s_AudioSceneView.Repaint(); } } diff --git a/Editor/Mono/SceneView/SceneViewToolbars.cs b/Editor/Mono/SceneView/SceneViewToolbars.cs index 010748c4cd..98dfdf547c 100644 --- a/Editor/Mono/SceneView/SceneViewToolbars.cs +++ b/Editor/Mono/SceneView/SceneViewToolbars.cs @@ -83,6 +83,7 @@ public SceneViewToolBar() : base( "SceneView/Scene Visibility", "SceneView/Render Doc", "SceneView/Metal Capture", + "SceneView/Layers", "SceneView/Scene Camera", "SceneView/Gizmos") {} } diff --git a/Editor/Mono/Scripting/ScriptCompilation/AssemblyBuilder.cs b/Editor/Mono/Scripting/ScriptCompilation/AssemblyBuilder.cs index 4138547b8e..2d7302543a 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/AssemblyBuilder.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/AssemblyBuilder.cs @@ -119,7 +119,7 @@ internal bool Build(EditorCompilation editorCompilation) editorCompilation, $"{(int)assembly.BuildTarget}{"AB"}", UnityBeeDriver.CacheMode.Off, - beeAssemblyBuilderDirectory, + beeAssemblyBuilderDirectoryInProjectDirectory, useScriptUpdater:false); buildRequest.DataForBuildProgram.Add(() => BeeScriptCompilation.ScriptCompilationDataFor( editorCompilation, diff --git a/Editor/Mono/Scripting/ScriptCompilation/BeeDriver/UnityBeeDriver.cs b/Editor/Mono/Scripting/ScriptCompilation/BeeDriver/UnityBeeDriver.cs index 16669fd0c4..262fd5e5f2 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/BeeDriver/UnityBeeDriver.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/BeeDriver/UnityBeeDriver.cs @@ -25,7 +25,7 @@ static class UnityBeeDriver internal static readonly string BeeBackendExecutable = new NPath($"{EditorApplication.applicationContentsPath}/bee_backend{BeeScriptCompilation.ExecutableExtension}").ToString(); internal static readonly string BeeCacheToolExecutable = $"{EditorApplication.applicationContentsPath}/Tools/BuildPipeline/BeeLocalCacheTool{BeeScriptCompilation.ExecutableExtension}"; internal static readonly string BeeCacheDirEnvVar = "BEE_CACHE_DIRECTORY"; - internal static string BeeCacheDir => Environment.GetEnvironmentVariable(BeeCacheDirEnvVar) ?? new NPath($"{InternalEditorUtility.userAppDataFolder}/cache/bee").ToString(SlashMode.Native); + internal static string BeeCacheDir => Environment.GetEnvironmentVariable(BeeCacheDirEnvVar) ?? new NPath($"{OSUtil.GetDefaultCachePath()}/bee").ToString(SlashMode.Native); [Serializable] internal class BeeBackendInfo @@ -142,7 +142,7 @@ public static BuildRequest BuildRequestFor( string dagName, string dagDirectory, bool useScriptUpdater, - string projectDirectory, + NPath projectDirectory, ILPostProcessingProgram ilpp, CacheMode cacheMode, StdOutMode stdoutMode, @@ -152,7 +152,7 @@ public static BuildRequest BuildRequestFor( // getting the property value enforces that as it makes sure the server is running and answering a ping request var ilppNamedPipeOrSocket = ilpp.EnsureRunningAndGetSocketOrNamedPipe(); - NPath dagDir = dagDirectory ?? "Library/Bee"; + NPath dagDir = dagDirectory ?? projectDirectory.Combine("Library/Bee"); RecreateDagDirectoryIfNeeded(dagDir); var performingPlayerBuild = UnityBeeDriverProfilerSession.PerformingPlayerBuild; NPath profilerOutputFile = performingPlayerBuild ? UnityBeeDriverProfilerSession.GetTraceEventsOutputForPlayerBuild() : $"{dagDir}/fullprofile.json"; @@ -160,7 +160,7 @@ public static BuildRequest BuildRequestFor( { BuildProgram = buildProgram, BackendProgram = beeBackendProgram ?? UnityBeeBackendProgram(cacheMode, stdoutMode), - ProjectRoot = projectDirectory, + ProjectRoot = projectDirectory.ToString(), DagName = dagName, BuildStateDirectory = dagDir.EnsureDirectoryExists().ToString(), ProfilerOutputFile = profilerOutputFile.ToString(), @@ -185,7 +185,6 @@ public static BuildRequest BuildRequestFor( UnityVersion = Application.unityVersion, UnityVersionNumeric = new BeeBuildProgramCommon.Data.Version(Application.unityVersionVer, Application.unityVersionMaj, Application.unityVersionMin), UnitySourceCodePath = Unsupported.IsSourceBuild(false) ? Unsupported.GetBaseUnityDeveloperFolder() : null, - AdvancedLicense = PlayerSettings.advancedLicense, Batchmode = InternalEditorUtility.inBatchMode, EmitDataForBeeWhy = (Debug.GetDiagnosticSwitch("EmitDataForBeeWhy").value as bool?)?? false, NamedPipeOrUnixSocket = ilppNamedPipeOrSocket, diff --git a/Editor/Mono/Scripting/ScriptCompilation/CustomScriptAssembly.cs b/Editor/Mono/Scripting/ScriptCompilation/CustomScriptAssembly.cs index 7b5d10b7a8..8dc1919d90 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/CustomScriptAssembly.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/CustomScriptAssembly.cs @@ -300,6 +300,7 @@ public AssemblyFlags AssemblyFlags public static List Platforms { get; private set; } public static CustomScriptAssemblyPlatform[] DeprecatedPlatforms { get; private set; } + public static string[] RenamedPlatforms { get; private set; } static CustomScriptAssembly() { @@ -360,6 +361,10 @@ static CustomScriptAssembly() new CustomScriptAssemblyPlatform("Lumin", BuildTarget.Lumin), new CustomScriptAssemblyPlatform("Stadia", BuildTarget.Stadia), }; + RenamedPlatforms = new string[] + { + "Bratwurst", + }; #pragma warning restore 0618 } @@ -520,6 +525,10 @@ public static bool IsDeprecatedPlatformName(string name) if (string.Equals(platform.Name, name, System.StringComparison.OrdinalIgnoreCase)) return true; + foreach(var platformName in RenamedPlatforms) + if (string.Equals(platformName, name, System.StringComparison.OrdinalIgnoreCase)) + return true; + return false; } diff --git a/Editor/Mono/Scripting/ScriptCompilation/EditorCompilation.cs b/Editor/Mono/Scripting/ScriptCompilation/EditorCompilation.cs index 50b6798961..dfe30f702a 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/EditorCompilation.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/EditorCompilation.cs @@ -928,10 +928,31 @@ public ScriptAssemblySettings CreateScriptAssemblySettings(BuildTarget buildTarg return CreateScriptAssemblySettings(buildTarget, EditorUserBuildSettings.GetActiveSubtargetFor(buildTarget), options, extraScriptingDefines); } + static private void ValidateSubtarget(BuildTarget buildTarget, ref int subtarget) + { + // When building for standalone, the Default subtarget means to use the current active one. + if (BuildPipeline.GetBuildTargetGroup(buildTarget) != BuildTargetGroup.Standalone) + return; + + var standaloneSubtarget = (StandaloneBuildSubtarget)subtarget; + switch (standaloneSubtarget) + { + case StandaloneBuildSubtarget.Default: + subtarget = EditorUserBuildSettings.GetActiveSubtargetFor(buildTarget); + break; + case StandaloneBuildSubtarget.Player: + case StandaloneBuildSubtarget.Server: + break; + default: + throw new ArgumentException($"Invalid subtarget {standaloneSubtarget} for build target {buildTarget}"); + } + } + public ScriptAssemblySettings CreateScriptAssemblySettings(BuildTarget buildTarget, int subtarget, EditorScriptCompilationOptions options, string[] extraScriptingDefines) { var predefinedAssembliesCompilerOptions = new ScriptCompilerOptions(); - var namedBuildTarget = NamedBuildTarget.FromActiveSettings(buildTarget); + ValidateSubtarget(buildTarget, ref subtarget); + var namedBuildTarget = NamedBuildTarget.FromTargetAndSubtarget(buildTarget, subtarget); if ((options & EditorScriptCompilationOptions.BuildingPredefinedAssembliesAllowUnsafeCode) == EditorScriptCompilationOptions.BuildingPredefinedAssembliesAllowUnsafeCode) { diff --git a/Editor/Mono/Search/OpenSearchHelper.cs b/Editor/Mono/Search/OpenSearchHelper.cs index 83b9098676..044d12cb00 100644 --- a/Editor/Mono/Search/OpenSearchHelper.cs +++ b/Editor/Mono/Search/OpenSearchHelper.cs @@ -15,8 +15,9 @@ static class Styles public static GUIContent gotoSearch = EditorGUIUtility.TrIconContent("SearchJump Icon"); } - const string k_SearchAllShortcutName = "Main Menu/Edit/Search/Search All..."; - const string k_OpenSearchInContextCommand = "OpenQuickSearchInContext"; + internal const string k_SearchMenuName = "Edit/Search/Search All..."; + internal const string k_SearchAllShortcutName = $"Main Menu/{k_SearchMenuName}"; + public const string k_OpenSearchInContextCommand = "OpenQuickSearchInContext"; static ShortcutBinding s_ShortcutBinding = ShortcutBinding.empty; public static ShortcutBinding shortcutBinding diff --git a/Editor/Mono/SerializedObject.bindings.cs b/Editor/Mono/SerializedObject.bindings.cs index 45a53cae98..410fe5f7ee 100644 --- a/Editor/Mono/SerializedObject.bindings.cs +++ b/Editor/Mono/SerializedObject.bindings.cs @@ -85,6 +85,19 @@ public SerializedProperty FindProperty(string propertyPath) return null; } + // Find serialized property by name ignoring case. + internal SerializedProperty FindPropertyIgnoreCase(string propertyPath) + { + SerializedProperty i = GetIterator_Internal(); + // This is so the garbage collector won't clean up SerializedObject behind the scenes, + // when we are still iterating properties + i.m_SerializedObject = this; + if (i.FindPropertyIgnoreCaseInternal(propertyPath)) + return i; + else + return null; + } + /// /// Given a path of the form "managedReferences[refid].field" this finds the first field /// that references that reference id and returns a serialized property based on that path. diff --git a/Editor/Mono/SerializedProperty.bindings.cs b/Editor/Mono/SerializedProperty.bindings.cs index b303123fc7..4e986e4abf 100644 --- a/Editor/Mono/SerializedProperty.bindings.cs +++ b/Editor/Mono/SerializedProperty.bindings.cs @@ -513,6 +513,9 @@ public void ClearArray() [NativeName("FindProperty")] extern internal bool FindPropertyInternal(string propertyPath); + [NativeName("FindPropertyIgnoreCase")] + extern internal bool FindPropertyIgnoreCaseInternal(string propertyPath); + [NativeName("FindFirstPropertyFromManagedReferencePath")] extern internal bool FindFirstPropertyFromManagedReferencePathInternal(string managedReferencePath); diff --git a/Editor/Mono/UIElements/Controls/CurveField.cs b/Editor/Mono/UIElements/Controls/CurveField.cs index e656fe79ed..dbcb4037b5 100644 --- a/Editor/Mono/UIElements/Controls/CurveField.cs +++ b/Editor/Mono/UIElements/Controls/CurveField.cs @@ -369,7 +369,7 @@ void FillCurveData() m_Content.SetMesh(m_Mesh); } - if (curve.keys.Length < 2) + if (curve == null || curve.keys.Length < 2) return; Vector3[] vertices = m_Mesh.vertices; Vector3[] normals = m_Mesh.normals; diff --git a/Editor/Mono/UIElements/Controls/LayerField.cs b/Editor/Mono/UIElements/Controls/LayerField.cs index a2b58d49fd..23857957d1 100644 --- a/Editor/Mono/UIElements/Controls/LayerField.cs +++ b/Editor/Mono/UIElements/Controls/LayerField.cs @@ -207,7 +207,7 @@ internal override void AddMenuItems(IGenericMenu menu) { var item = layerList[i]; var menuItemIndex = m_Choices[i]; - var isSelected = (menuItemIndex == value); + var isSelected = (menuItemIndex == value) && !showMixedValue; menu.AddItem(item, isSelected, () => ChangeValueFromMenu(menuItemIndex)); } menu.AddSeparator(String.Empty); diff --git a/Editor/Mono/UIElements/Controls/MaskField.cs b/Editor/Mono/UIElements/Controls/MaskField.cs index c169cd4523..c136622160 100644 --- a/Editor/Mono/UIElements/Controls/MaskField.cs +++ b/Editor/Mono/UIElements/Controls/MaskField.cs @@ -232,9 +232,6 @@ internal override string GetListItemToDisplay(TChoice item) internal string GetDisplayedValue(int itemIndex) { - if (showMixedValue) - return mixedValueString; - var newValueToShowUser = ""; switch (itemIndex) @@ -368,7 +365,7 @@ internal override void AddMenuItems(IGenericMenu menu) foreach (var item in m_Choices) { var maskOfItem = GetMaskValueOfItem(item); - var isSelected = IsItemSelected(maskOfItem); + var isSelected = IsItemSelected(maskOfItem) && !showMixedValue; menu.AddItem(GetListItemToDisplay(MaskToValue(maskOfItem)), isSelected, () => ChangeValueFromMenu(item)); } @@ -421,9 +418,9 @@ int UpdateMaskIfEverything(int currentMask) return newMask; } - private void ChangeValueFromMenu(string menuItem) + internal void ChangeValueFromMenu(string menuItem) { - var newMask = ValueToMask(value); + var newMask = showMixedValue ? 0 : ValueToMask(value); var maskFromItem = GetMaskValueOfItem(menuItem); switch (maskFromItem) { @@ -602,7 +599,7 @@ internal override string GetListItemToDisplay(int itemIndex) internal override string GetValueToDisplay() { - string displayedValue = GetDisplayedValue(rawValue); + string displayedValue = showMixedValue ? mixedValueString : GetDisplayedValue(rawValue); if (ShouldFormatSelectedValue()) displayedValue = m_FormatSelectedValueCallback(displayedValue); return displayedValue; diff --git a/Editor/Mono/UIElements/Controls/ObjectField.cs b/Editor/Mono/UIElements/Controls/ObjectField.cs index 8869332e7b..dc518b13d0 100644 --- a/Editor/Mono/UIElements/Controls/ObjectField.cs +++ b/Editor/Mono/UIElements/Controls/ObjectField.cs @@ -453,16 +453,22 @@ public ObjectField(string label) }); } + internal event Action SelectorClosed; + internal void OnObjectChanged(Object obj) { value = TryReadComponentFromGameObject(obj, objectType); } + internal void OnObjectSelectorClosed(Object obj) + { + SelectorClosed?.Invoke(obj, ObjectSelector.SelectionCanceled()); + } + internal void ShowObjectSelector() { - // Since we have nothing useful to do on the object selector closing action, we just do not assign any callback // All the object changes will be notified through the OnObjectChanged and a "cancellation" (Escape key) on the ObjectSelector is calling the closing callback without any good object - ObjectSelector.get.Show(value, objectType, null, allowSceneObjects, null, null, OnObjectChanged); + ObjectSelector.get.Show(value, objectType, null, allowSceneObjects, null, OnObjectSelectorClosed, OnObjectChanged); m_OnObjectSelectorShow?.Invoke(); } diff --git a/Editor/Mono/UIElements/Controls/PropertyField.cs b/Editor/Mono/UIElements/Controls/PropertyField.cs index 4d86fd06fd..da25a98f66 100644 --- a/Editor/Mono/UIElements/Controls/PropertyField.cs +++ b/Editor/Mono/UIElements/Controls/PropertyField.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; +using Unity.Properties; using UnityEngine; using UnityEngine.UIElements; @@ -16,6 +17,7 @@ namespace UnityEditor.UIElements /// public class PropertyField : VisualElement, IBindable { + static readonly BindingId labelProperty = nameof(label); private static readonly Regex s_MatchPPtrTypeName = new Regex(@"PPtr\<(\w+)\>"); internal static readonly string foldoutTitleBoundLabelProperty = "unity-foldout-bound-title"; internal static readonly string decoratorDrawersContainerClassName = "unity-decorator-drawers-container"; @@ -100,8 +102,19 @@ public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext /// /// Optionally overwrite the label of the generate property field. If no label is provided the string will be taken from the SerializedProperty. /// - public string label { get; set; } + [CreateProperty] + public string label + { + get => m_Label; + set + { + if (m_Label == value) return; + m_Label = value; + NotifyPropertyChanged(labelProperty); + } + } + string m_Label; SerializedObject m_SerializedObject; internal SerializedObject serializedObject => m_SerializedObject; @@ -279,6 +292,8 @@ void Reset(SerializedProperty newProperty) m_ChildField?.Unbind(); m_ChildField = null; + m_CustomPropertyGUI?.Unbind(); + m_CustomPropertyGUI = null; m_DecoratorDrawersContainer = null; Clear(); @@ -298,7 +313,11 @@ void Reset(SerializedProperty newProperty) if (handler.hasPropertyDrawer) { handler.propertyDrawer.m_PreferredLabel = label ?? serializedProperty.localizedDisplayName; - customPropertyGUI = handler.propertyDrawer.CreatePropertyGUI(m_SerializedProperty); + + // UUM-12851: copy the property, as user code may iterate on it or leave it in a different state. + customPropertyGUI = handler.propertyDrawer.CreatePropertyGUI(m_SerializedProperty.Copy()); + + m_CustomPropertyGUI = customPropertyGUI; if (customPropertyGUI == null) { @@ -327,7 +346,8 @@ void Reset(SerializedProperty newProperty) if (m_SerializedProperty.propertyType == SerializedPropertyType.ManagedReference) { - BindingExtensions.TrackPropertyValue(m_ChildField, m_SerializedProperty, + var fieldToBind = m_ChildField == null ? m_CustomPropertyGUI : m_ChildField; + BindingExtensions.TrackPropertyValue(fieldToBind, m_SerializedProperty, (e) => this.Bind(m_SerializedProperty.serializedObject)); } } @@ -550,6 +570,7 @@ private void UpdateArrayFoldout( /// stores the child field if there is only a single child. Used for updating bindings when this field is rebound. /// private VisualElement m_ChildField; + private VisualElement m_CustomPropertyGUI; private VisualElement m_imguiChildField; private VisualElement m_ChildrenContainer; @@ -777,6 +798,7 @@ VisualElement ConfigureToggleButtonGroup(ToggleButtonGroup buttonGroup, Serializ { buttonGroup = factory(); buttonGroup.AddToClassList(BaseField.alignedFieldUssClassName); + buttonGroup.AddToClassList(ToggleButtonGroup.ussClassName + "--fixed-size"); buttonGroup.RegisterValueChangedCallback(OnToggleGroupChanged); } diff --git a/Editor/Mono/UIElements/Controls/TagField.cs b/Editor/Mono/UIElements/Controls/TagField.cs index 660b7779d2..bbd38ca48e 100644 --- a/Editor/Mono/UIElements/Controls/TagField.cs +++ b/Editor/Mono/UIElements/Controls/TagField.cs @@ -187,7 +187,7 @@ internal override void AddMenuItems(IGenericMenu menu) choices = InitializeTags(); foreach (var menuItem in choices) { - var isSelected = (menuItem == value); + var isSelected = (menuItem == value) && !showMixedValue; menu.AddItem(menuItem, isSelected, () => ChangeValueFromMenu(menuItem)); } menu.AddSeparator(String.Empty); diff --git a/Editor/Mono/UIElements/DefaultMainToolbar.cs b/Editor/Mono/UIElements/DefaultMainToolbar.cs index 690d8b1724..29b309fea3 100644 --- a/Editor/Mono/UIElements/DefaultMainToolbar.cs +++ b/Editor/Mono/UIElements/DefaultMainToolbar.cs @@ -41,7 +41,6 @@ static IEnumerable rightToolbar { // Modules/EditorToolbar/ToolbarElements/*.cs yield return "Editor Utility/Layout"; - yield return "Editor Utility/Layers"; yield return "Editor Utility/Search"; yield return "Editor Utility/Modes"; yield return "Package Manager/PreviewPackagesInUse"; diff --git a/Editor/Mono/UIElements/Inspector/InspectorElement.cs b/Editor/Mono/UIElements/Inspector/InspectorElement.cs index 9521c11472..c0dd6ff7f1 100644 --- a/Editor/Mono/UIElements/Inspector/InspectorElement.cs +++ b/Editor/Mono/UIElements/Inspector/InspectorElement.cs @@ -210,6 +210,8 @@ public UxmlTraits() /// internal VisualElement livePropertyYellowBarsContainer { get; private set; } + internal EditorGUIUtility.ComparisonViewMode comparisonViewMode { get; set; } + /// /// Gets or sets the default inspector framework to use for this inspector. This will take affect during the next bind. /// @@ -680,7 +682,9 @@ VisualElement CreateInspectorElementUsingIMGUI(Editor targetEditor) var originalViewWidth = EditorGUIUtility.currentViewWidth; var originalHierarchyMode = EditorGUIUtility.hierarchyMode; + var originalComparisonMode = EditorGUIUtility.comparisonViewMode; EditorGUIUtility.hierarchyMode = true; + EditorGUIUtility.comparisonViewMode = comparisonViewMode; var originalWideMode = SetWideModeForWidth(inspector); @@ -764,6 +768,7 @@ VisualElement CreateInspectorElementUsingIMGUI(Editor targetEditor) EditorGUIUtility.wideMode = originalWideMode; EditorGUIUtility.hierarchyMode = originalHierarchyMode; EditorGUIUtility.currentViewWidth = originalViewWidth; + EditorGUIUtility.comparisonViewMode = originalComparisonMode; } } }; diff --git a/Editor/Mono/Undo/EditorObjectChangeEvents.cs b/Editor/Mono/Undo/EditorObjectChangeEvents.cs index 9affc455a7..55430a2543 100644 --- a/Editor/Mono/Undo/EditorObjectChangeEvents.cs +++ b/Editor/Mono/Undo/EditorObjectChangeEvents.cs @@ -48,7 +48,10 @@ public enum ObjectChangeKind : ushort UpdatePrefabInstances = 11, // Children order change - ChangeChildrenOrder = 12 + ChangeChildrenOrder = 12, + + // Root order change + ChangeRootOrder = 13, } public static class ObjectChangeEvents @@ -144,6 +147,22 @@ public ChangeChildrenOrderEventArgs(int instanceId, Scene scene) private Scene m_Scene; } + [StructLayout(LayoutKind.Sequential)] + public struct ChangeRootOrderEventArgs + { + public int instanceId => m_InstanceId; + public Scene scene => m_Scene; + + public ChangeRootOrderEventArgs(int instanceId, Scene scene) + { + m_InstanceId = instanceId; + m_Scene = scene; + } + + private int m_InstanceId; + private Scene m_Scene; + } + [StructLayout(LayoutKind.Sequential)] public struct ChangeSceneEventArgs { @@ -388,6 +407,9 @@ public void GetChangeGameObjectParentEvent(int eventIdx, out ChangeGameObjectPar public void GetChangeChildrenOrderEvent(int eventIdx, out ChangeChildrenOrderEventArgs data) => ExtractEvent(eventIdx, ObjectChangeKind.ChangeChildrenOrder, out data); + public void GetChangeRootOrderEvent(int eventIdx, out ChangeRootOrderEventArgs data) => + ExtractEvent(eventIdx, ObjectChangeKind.ChangeRootOrder, out data); + public void GetChangeGameObjectOrComponentPropertiesEvent(int eventIdx, out ChangeGameObjectOrComponentPropertiesEventArgs data) => ExtractEvent(eventIdx, ObjectChangeKind.ChangeGameObjectOrComponentProperties, out data); diff --git a/Editor/Mono/UnityConnect/UnityConnect.bindings.cs b/Editor/Mono/UnityConnect/UnityConnect.bindings.cs index eaa4b9811d..24ae446a81 100644 --- a/Editor/Mono/UnityConnect/UnityConnect.bindings.cs +++ b/Editor/Mono/UnityConnect/UnityConnect.bindings.cs @@ -491,17 +491,6 @@ public bool isDisableUserLogin } } - [NativeMethod("isDisableCollabWindow")] - private static extern bool isDisableCollabWindow_Internal(); - public bool isDisableCollabWindow - { - get - { - return isDisableCollabWindow_Internal(); - } - } - - public string GetEnvironment() { return GetConfigEnvironment(); @@ -752,26 +741,5 @@ public bool canBuildWithUPID { get { return CanBuildWithUPID(); } } - - [NativeMethod("IsCollabAcceleratorInUse")] - private static extern bool IsCollabAcceleratorInUse_Internal(); - public bool isCollabAcceleratorInUse - { - get { return IsCollabAcceleratorInUse_Internal(); } - } - - [NativeMethod("GetCollabAcceleratorId")] - private static extern string GetCollabAcceleratorId_Internal(); - public string collabAcceleratorId - { - get { return GetCollabAcceleratorId_Internal(); } - } - - [NativeMethod("GetCollabAcceleratorName")] - private static extern string GetCollabAcceleratorName_Internal(); - public string collabAcceleratorName - { - get { return GetCollabAcceleratorName_Internal(); } - } } } diff --git a/Editor/Mono/Utils/SearchUtils.cs b/Editor/Mono/Utils/SearchUtils.cs index 8912adb40c..f9f520921d 100644 --- a/Editor/Mono/Utils/SearchUtils.cs +++ b/Editor/Mono/Utils/SearchUtils.cs @@ -6,6 +6,11 @@ namespace UnityEditor { + interface ISearchableContainer + { + string searchText { get; } + } + static class SearchUtils { internal static bool MatchSearch(string searchContext, string content) diff --git a/Modules/AndroidJNI/AndroidDevice.bindings.cs b/Modules/AndroidJNI/AndroidDevice.bindings.cs index bd94072e79..213ece791e 100644 --- a/Modules/AndroidJNI/AndroidDevice.bindings.cs +++ b/Modules/AndroidJNI/AndroidDevice.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 UnityEngine.Bindings; using UnityEngine.Scripting.APIUpdating; @@ -10,6 +11,7 @@ namespace UnityEngine.Android public enum AndroidHardwareType { Generic, + [Obsolete("ChromeOS is no longer supported.")] ChromeOS } diff --git a/Modules/AssetPipelineEditor/Public/MonoImporter.bindings.cs b/Modules/AssetPipelineEditor/Public/MonoImporter.bindings.cs index 49bcfb05ce..2527fb2910 100644 --- a/Modules/AssetPipelineEditor/Public/MonoImporter.bindings.cs +++ b/Modules/AssetPipelineEditor/Public/MonoImporter.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.Collections.Generic; using UnityEngine; using UnityEngine.Bindings; @@ -14,6 +15,9 @@ public class MonoImporter : AssetImporter { public extern void SetDefaultReferences(string[] name, Object[] target); + [FreeFunction("MonoImporterBindings::GetDefaultReferencesInternal")] + internal static extern void GetDefaultReferencesInternal([NotNull] MonoScript script, List names, List targets); + [FreeFunction("MonoImporterBindings::GetAllRuntimeMonoScripts")] public static extern MonoScript[] GetAllRuntimeMonoScripts(); diff --git a/Modules/Audio/Public/ScriptBindings/AudioMixer.bindings.cs b/Modules/Audio/Public/ScriptBindings/AudioMixer.bindings.cs index 4c244d6e43..90f75422a9 100644 --- a/Modules/Audio/Public/ScriptBindings/AudioMixer.bindings.cs +++ b/Modules/Audio/Public/ScriptBindings/AudioMixer.bindings.cs @@ -68,8 +68,5 @@ internal void TransitionToSnapshot(AudioMixerSnapshot snapshot, float timeToReac [NativeMethod("AudioMixerBindings::GetAbsoluteAudibilityFromGroup", HasExplicitThis = true, IsFreeFunction = true)] internal extern float GetAbsoluteAudibilityFromGroup(AudioMixerGroup group); - - [NativeMethod] - internal extern bool HasValidSnapshots(); } } diff --git a/Modules/AudioEditor/ScriptBindings/AudioMixerController.bindings.cs b/Modules/AudioEditor/ScriptBindings/AudioMixerController.bindings.cs index 68b392ec92..120c8b2b11 100644 --- a/Modules/AudioEditor/ScriptBindings/AudioMixerController.bindings.cs +++ b/Modules/AudioEditor/ScriptBindings/AudioMixerController.bindings.cs @@ -113,5 +113,7 @@ public List CachedSelection [FreeFunction("AudioMixerController::EditingTargetSnapshot")] public extern static bool EditingTargetSnapshot(); + [NativeMethod] + internal extern bool HasValidSnapshots(); } } diff --git a/Modules/BuildPipeline/Editor/Managed/BuildDefines.cs b/Modules/BuildPipeline/Editor/Managed/BuildDefines.cs index 54e5508c39..f8e1871824 100644 --- a/Modules/BuildPipeline/Editor/Managed/BuildDefines.cs +++ b/Modules/BuildPipeline/Editor/Managed/BuildDefines.cs @@ -6,6 +6,8 @@ using UnityEngine; using UnityEngine.Scripting; using System.Collections.Generic; +using UnityEditor.Build.Profile; +using System; namespace UnityEditor.Build { @@ -26,5 +28,18 @@ public static string[] GetScriptCompilationDefines(BuildTarget target, string[] hashSet.CopyTo(array); return array; } + + [RequiredByNativeCode] + public static string[] GetBuildProfileScriptDefines() + { + if (!EditorUserBuildSettings.isBuildProfileAvailable) + return EditorUserBuildSettings.GetActiveProfileYamlScriptingDefines(); + + if (BuildProfileContext.instance.activeProfile == null) + return Array.Empty(); + + var profile = BuildProfileContext.instance.activeProfile; + return profile.scriptingDefines; + } } } diff --git a/Modules/BuildPipeline/Editor/Managed/BuildUsageTagGlobal.cs b/Modules/BuildPipeline/Editor/Managed/BuildUsageTagGlobal.cs index 309e5f075a..26b2e002db 100644 --- a/Modules/BuildPipeline/Editor/Managed/BuildUsageTagGlobal.cs +++ b/Modules/BuildPipeline/Editor/Managed/BuildUsageTagGlobal.cs @@ -26,6 +26,7 @@ public struct BuildUsageTagGlobal internal bool m_SubtractiveUsed; internal bool m_HybridRendererPackageUsed; internal bool m_BuildForServer; + internal bool m_LODFadeCrossfade; public static BuildUsageTagGlobal operator|(BuildUsageTagGlobal x, BuildUsageTagGlobal y) { @@ -41,6 +42,7 @@ public struct BuildUsageTagGlobal results.m_HybridRendererPackageUsed = x.m_HybridRendererPackageUsed | y.m_HybridRendererPackageUsed; results.m_BrgShaderStripModeMask = x.m_BrgShaderStripModeMask | y.m_BrgShaderStripModeMask; results.m_BuildForServer = x.m_BuildForServer | y.m_BuildForServer; + results.m_LODFadeCrossfade = x.m_LODFadeCrossfade | y.m_LODFadeCrossfade; return results; } } diff --git a/Modules/BuildProfileEditor/AssetImportOverridesWindow.cs b/Modules/BuildProfileEditor/AssetImportOverridesWindow.cs index af72816251..02bfec747c 100644 --- a/Modules/BuildProfileEditor/AssetImportOverridesWindow.cs +++ b/Modules/BuildProfileEditor/AssetImportOverridesWindow.cs @@ -115,7 +115,7 @@ internal void CreateGUI() textureCompression.value = k_TextureCompressionLabels[texCompression]; } - internal void ApplyCurrentAssetImportOverrides() + void ApplyCurrentAssetImportOverrides() { if (m_CurrOverrideMaxTextureSize < 0) { diff --git a/Modules/BuildProfileEditor/BuildProfileEditor.cs b/Modules/BuildProfileEditor/BuildProfileEditor.cs index 2e35d111b0..b7acc5d84d 100644 --- a/Modules/BuildProfileEditor/BuildProfileEditor.cs +++ b/Modules/BuildProfileEditor/BuildProfileEditor.cs @@ -6,6 +6,8 @@ using UnityEditor.Modules; using UnityEditor.Build.Profile.Elements; using UnityEngine.UIElements; +using UnityEditor.UIElements; +using UnityEngine; namespace UnityEditor.Build.Profile { @@ -26,10 +28,12 @@ internal class BuildProfileEditor : Editor const string k_SceneListFoldoutClassicButton = "scene-list-foldout-classic-button"; const string k_CompilingWarningHelpBox = "compiling-warning-help-box"; const string k_VirtualTextureWarningHelpBox = "virtual-texture-warning-help-box"; - + const string k_PlayerScriptingDefinesFoldout = "scripting-defines-foldout"; BuildProfileSceneList m_SceneList; HelpBox m_CompilingWarningHelpBox; HelpBox m_VirtualTexturingHelpBox; + Button recompileDefinesButton; + Button revertDefinesButton; BuildProfile m_Profile; public BuildProfileWindow parent { get; set; } @@ -43,6 +47,9 @@ internal class BuildProfileEditor : Editor internal BuildProfile buildProfile => m_Profile; IBuildProfileExtension m_PlatformExtension = null; + Foldout m_PlayerScriptingDefinesFoldout; + + BuildProfilePlayerSettingsEditor m_ProfilePlayerSettingsEditor = null; public BuildProfileEditor() { @@ -102,6 +109,7 @@ public override VisualElement CreateInspectorGUI() sharedSettingsInfoHelpBox.text = TrText.sharedSettingsInfo; AddSceneList(root, profile); + AddScriptingDefineListView(root); if (!BuildProfileContext.IsClassicPlatformProfile(profile)) sharedSettingsInfoHelpBox.Hide(); @@ -109,16 +117,18 @@ public override VisualElement CreateInspectorGUI() { var button = root.Q