using System; using System.Reflection; using System.Runtime.CompilerServices; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; #if UNITY_EDITOR using PackageInfo = UnityEditor.PackageManager.PackageInfo; #endif [assembly: InternalsVisibleTo("Unity.RenderPipelines.Core.Editor.Tests")] namespace UnityEngine.Rendering { /// /// Attribute to define the help url /// /// /// [CoreRPHelpURLAttribute("Volume")] /// public class Volume : MonoBehaviour /// [Conditional("UNITY_EDITOR")] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum, AllowMultiple = false)] public class CoreRPHelpURLAttribute : HelpURLAttribute { /// /// The constructor of the attribute /// /// The name of the documentation page. /// The package name, defaulting to "com.unity.render-pipelines.core". public CoreRPHelpURLAttribute(string pageName, string packageName = "com.unity.render-pipelines.core") : base(DocumentationInfo.GetPageLink(packageName, pageName, "")) { } /// /// The constructor of the attribute /// /// The name of the documentation page. /// The hash specifying a section within the page. /// The package name, defaulting to "com.unity.render-pipelines.core". public CoreRPHelpURLAttribute(string pageName, string pageHash, string packageName = "com.unity.render-pipelines.core") : base(DocumentationInfo.GetPageLink(packageName, pageName, pageHash)) { } } /// /// Use this attribute to define documentation url for the current Render Pipeline. /// /// /// The URL is resolved at access time based on the active RenderPipelineAsset /// type. If that type carries a the URL is /// built for the declared ; otherwise it falls back /// to the package documentation site for the package that owns the pipeline asset. /// /// /// [CurrentPipelineHelpURLAttribute("Volume")] /// public class Volume : MonoBehaviour /// [Conditional("UNITY_EDITOR")] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum, AllowMultiple = false)] public class CurrentPipelineHelpURLAttribute : HelpURLAttribute { private string pageName { get; } private string pageHash { get; } /// /// The constructor of the attribute /// /// The name of the documentation page. /// The name of the section on the documentation page. public CurrentPipelineHelpURLAttribute(string pageName, string pageHash = "") : base(null) { this.pageName = pageName; this.pageHash = pageHash; } /// /// Returns the URL to the given page in the current Render Pipeline documentation. /// public override string URL { get { #if UNITY_EDITOR if (!GraphicsSettings.isScriptableRenderPipelineEnabled) return string.Empty; return DocumentationInfo.BuildPipelineHelpUrl(GraphicsSettings.currentRenderPipelineAssetType, pageName, pageHash); #else return string.Empty; #endif } } } /// /// Use this attribute to define a documentation URL that is only active when a specific Render Pipeline is in use. /// /// /// /// [PipelineHelpURL("HDRenderPipelineAsset", "hdrp-page-name")] /// [PipelineHelpURL("UniversalRenderPipelineAsset", "urp-page-name")] /// public class MyHDRPComponent : MonoBehaviour { /* ... */ } /// /// /// /// The URL will only be generated if the active Scriptable Render Pipeline Asset's type name exactly matches the pipelineName provided. /// /// [Conditional("UNITY_EDITOR")] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum, AllowMultiple = true)] public class PipelineHelpURLAttribute : HelpURLAttribute { private string pipelineName { get; } private string pageName { get; } private string pageHash { get; } /// /// Initializes the attribute to link to a specific documentation page for a named Render Pipeline. /// /// The exact Type name of the Render Pipeline Asset (e.g., "UniversalRenderPipelineAsset", "HDRenderPipelineAsset") for which this URL is valid. /// The name of the documentation page. /// Optional. The specific section anchor (#) on the documentation page. public PipelineHelpURLAttribute(string pipelineName, string pageName, string pageHash = "") : base(null) { this.pipelineName = pipelineName; this.pageName = pageName; this.pageHash = pageHash; } /// /// Returns the URL to the specified page within the documentation for the designated Render Pipeline, /// but only if that pipeline is currently active. /// /// /// Checks if a Scriptable Render Pipeline is enabled and if its asset type name matches the pipelineName /// provided in the constructor. If conditions are met and package info is found, constructs the URL. /// Otherwise, returns an empty string. /// public override string URL { get { #if UNITY_EDITOR if (string.IsNullOrEmpty(pipelineName) || !GraphicsSettings.isScriptableRenderPipelineEnabled) return string.Empty; var pipelineType = GraphicsSettings.currentRenderPipelineAssetType; if (pipelineType.Name != pipelineName) return string.Empty; return DocumentationInfo.BuildPipelineHelpUrl(pipelineType, pageName, pageHash); #else return string.Empty; #endif } } } //We need to have only one version number amongst packages (so public) /// /// Documentation Info class. /// public class DocumentationInfo { /// /// Identifies where a Render Pipeline's user-facing documentation lives, so that /// and /// build URLs against the right base location. /// public enum Location { /// /// Pages live on the package documentation site /// (https://docs.unity3d.com/Packages/<package>@<version>/manual/<page>.html). /// This is the default when no is present. /// Package, /// /// Pages live in the Unity Manual /// (https://docs.unity3d.com/<version>/Documentation/Manual/<page>.html). /// Manual, } /// /// Apply this attribute to a RenderPipelineAsset type to declare where its /// user-facing documentation is hosted. Consumed by /// and to choose between Unity Manual URLs and /// the package documentation site. /// /// /// Editor-only: the attribute is stripped from non-Editor builds via /// , since the help URL machinery only runs in the Editor. /// /// /// /// [DocumentationInfo.Source(DocumentationInfo.Location.Manual)] /// public class UniversalRenderPipelineAsset : RenderPipelineAsset { /* ... */ } /// /// [Conditional("UNITY_EDITOR")] [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] public sealed class SourceAttribute : Attribute { /// The documentation location for the decorated pipeline asset type. public Location Location { get; } /// Creates the attribute with the given documentation location. /// Where the pipeline's documentation pages are hosted. public SourceAttribute(Location location) { Location = location; } } const string fallbackVersion = "13.1"; const string packageDocumentationUrl = "https://docs.unity3d.com/Packages/{0}@{1}/manual/"; const string url = packageDocumentationUrl + "{2}.html{3}"; const string k_ManualUrlFormat = "https://docs.unity3d.com/{0}/Documentation/Manual/{1}.html{2}"; const string k_ManualFallbackUrlFormat = "https://docs.unity3d.com/Manual/{0}.html{1}"; #if UNITY_EDITOR // Resolves a help URL for a page documented under a specific pipeline asset type. // The location (Unity Manual vs package site) is taken from a DocumentationInfo.SourceAttribute // on the pipeline asset type; without one, falls back to the package site for the // package that owns the type. internal static string BuildPipelineHelpUrl(Type pipelineAssetType, string pageName, string pageHash) { if (pipelineAssetType == null) return string.Empty; var source = pipelineAssetType.GetCustomAttribute(inherit: false); if (source != null && source.Location == Location.Manual) return GetManualLink(pageName, pageHash); if (DocumentationUtils.TryGetPackageInfoForType(pipelineAssetType, out var package, out var version)) return GetPackageLink(package, version, pageName, pageHash); return string.Empty; } #endif /// /// Current version of the documentation. /// public static string version { get { #if UNITY_EDITOR if (DocumentationUtils.TryGetPackageInfoForType(typeof(DocumentationInfo), out _, out var version)) return version; #endif return fallbackVersion; } } /// /// Generates a help URL for the given package and page name. /// /// The package name. /// The package version. /// The page name without the extension. /// The full URL of the page. public static string GetPackageLink(string packageName, string packageVersion, string pageName) => string.Format(url, packageName, packageVersion, pageName, ""); /// /// Generates a help URL for the given package, page name and section name. /// /// The package name. /// The package version. /// The page name without the extension. /// The section name on the documentation page. /// The full URL of the page. public static string GetPackageLink(string packageName, string packageVersion, string pageName, string pageHash) { if (!string.IsNullOrEmpty(pageHash) && !pageHash.StartsWith("#")) pageHash = $"#{pageHash}"; return string.Format(url, packageName, packageVersion, pageName, pageHash); } /// /// Generates a help url for the given package and page name /// /// The package name /// The page name without the extension. /// The full URL of the page. public static string GetPageLink(string packageName, string pageName) => string.Format(url, packageName, version, pageName, ""); /// /// Generates a help url for the given package and page name /// /// The package name /// The page name without the extension. /// The page hash /// The full URL of the page. public static string GetPageLink(string packageName, string pageName, string pageHash) { if (!string.IsNullOrEmpty(pageHash) && !pageHash.StartsWith("#")) pageHash = $"#{pageHash}"; return string.Format(url, packageName, version, pageName, pageHash); } /// /// Generates a help url to the index page for the provided package name and package version. /// /// The name of the package. /// The version of the package. /// The full URL to the default package documentation page. public static string GetDefaultPackageLink(string packageName, string packageVersion) => string.Format(packageDocumentationUrl, packageName, packageVersion); /// /// Generates a help url to the index page for the provided package name and package version. /// /// The name of the package. /// The full URL to the default package documentation page. public static string GetDefaultPackageLink(string packageName) => string.Format(packageDocumentationUrl, packageName, version); /// /// Generates a Unity Manual help URL for the given page. /// /// The page path relative to the Manual root, without the .html extension (for example "urp/Volumes"). /// Optional section anchor on the page, with or without the leading #. /// /// A versioned Manual URL such as /// https://docs.unity3d.com/6000.6/Documentation/Manual/urp/Volumes.html when /// the running Unity version can be determined, otherwise the unversioned /// fallback https://docs.unity3d.com/Manual/urp/Volumes.html. /// /// /// /// // Versioned: https://docs.unity3d.com/6000.6/Documentation/Manual/urp/Volumes.html /// // Fallback: https://docs.unity3d.com/Manual/urp/Volumes.html /// var url = DocumentationInfo.GetManualLink("urp/Volumes"); /// /// // With a section anchor. /// var sectionUrl = DocumentationInfo.GetManualLink("urp/features/rendering-debugger-reference", "lighting"); /// /// public static string GetManualLink(string pageName, string pageHash = "") { if (!string.IsNullOrEmpty(pageHash) && !pageHash.StartsWith("#")) pageHash = "#" + pageHash; #if UNITY_EDITOR if (UnityEditor.AssetDatabase.IsAssetImportWorkerProcess()) return string.Format(k_ManualFallbackUrlFormat, pageName, pageHash); var unityVersion = UnityEditorInternal.InternalEditorUtility.GetUnityVersion(); return string.Format(k_ManualUrlFormat, $"{unityVersion.Major}.{unityVersion.Minor}", pageName, pageHash); #else return string.Format(k_ManualFallbackUrlFormat, pageName, pageHash); #endif } } /// /// Set of utils for documentation /// public static class DocumentationUtils { /// /// Obtains the help url from an enum /// /// The enum with a /// [Optional] The current value of the enum /// The full url public static string GetHelpURL(TEnum mask = default) where TEnum : struct, IConvertible { var helpURLAttributes = mask .GetType() .GetCustomAttributes(typeof(HelpURLAttribute), false); return helpURLAttributes.Length == 0 ? string.Empty : $"{((HelpURLAttribute)helpURLAttributes[0]).URL}#{mask}"; } /// /// Obtains the help URL from a type. /// /// The type decorated with the HelpURL attribute. /// The full URL from the HelpURL attribute. If the attribute is not present, this value is null. /// Returns true if the attribute is present, and false otherwise. public static bool TryGetHelpURL(Type type, out string url) { var helpURLAttributes = type.GetCustomAttributes(typeof(HelpURLAttribute), true); for (int i = 0; i < helpURLAttributes.Length; i++) { var attr = (HelpURLAttribute)helpURLAttributes[i]; var attributeUrl = attr.URL; if (string.IsNullOrEmpty(attributeUrl)) continue; url = attributeUrl; return true; } url = null; return false; } #if UNITY_EDITOR /// /// Obtains package information for a specified type. /// /// The type used to retrieve package information. /// The name of the package containing the given type. /// The version number of the package containing the given type. Only Major.Minor will be returned as fix is not used for documentation. /// Returns true if the package information is found; otherwise, false. public static bool TryGetPackageInfoForType([DisallowNull] Type type, [NotNullWhen(true)] out string packageName, [NotNullWhen(true)] out string version) { var packageInfo = PackageInfo.FindForAssembly(type.Assembly); if (packageInfo == null) { packageName = null; version = null; return false; } packageName = packageInfo.name; version = packageInfo.version.Substring(0, packageInfo.version.LastIndexOf('.')); return true; } /// /// Obtains a help URL to the index page for the package documentation of a specified type. /// /// The type used to retrieve package information. /// The generated help URL to the package's index documentation page. /// Returns true if a valid help URL is retrieved; otherwise, false. public static bool TryGetDefaultHelpURL([DisallowNull] Type type, [NotNullWhen(true)] out string url) { url = string.Empty; if (TryGetPackageInfoForType(type, out var packageName, out var version)) url = DocumentationInfo.GetDefaultPackageLink(packageName, version); return !string.IsNullOrEmpty(url); } #endif } }